libgo: update to Go 1.11
[official-gcc.git] / libgo / go / net / conf.go
blob6cc4a99bd3502401a2a758ef6daa457bbffcd065
1 // Copyright 2015 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.
5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
7 package net
9 import (
10 "os"
11 "runtime"
12 "sync"
13 "syscall"
16 // conf represents a system's network configuration.
17 type conf struct {
18 // forceCgoLookupHost forces CGO to always be used, if available.
19 forceCgoLookupHost bool
21 netGo bool // go DNS resolution forced
22 netCgo bool // cgo DNS resolution forced
24 // machine has an /etc/mdns.allow file
25 hasMDNSAllow bool
27 goos string // the runtime.GOOS, to ease testing
28 dnsDebugLevel int
30 nss *nssConf
31 resolv *dnsConfig
34 var (
35 confOnce sync.Once // guards init of confVal via initConfVal
36 confVal = &conf{goos: runtime.GOOS}
39 // systemConf returns the machine's network configuration.
40 func systemConf() *conf {
41 confOnce.Do(initConfVal)
42 return confVal
45 func initConfVal() {
46 dnsMode, debugLevel := goDebugNetDNS()
47 confVal.dnsDebugLevel = debugLevel
48 confVal.netGo = netGo || dnsMode == "go"
49 confVal.netCgo = netCgo || dnsMode == "cgo"
51 if confVal.dnsDebugLevel > 0 {
52 defer func() {
53 switch {
54 case confVal.netGo:
55 if netGo {
56 println("go package net: built with netgo build tag; using Go's DNS resolver")
57 } else {
58 println("go package net: GODEBUG setting forcing use of Go's resolver")
60 case confVal.forceCgoLookupHost:
61 println("go package net: using cgo DNS resolver")
62 default:
63 println("go package net: dynamic selection of DNS resolver")
65 }()
68 // Darwin pops up annoying dialog boxes if programs try to do
69 // their own DNS requests. So always use cgo instead, which
70 // avoids that.
71 if runtime.GOOS == "darwin" {
72 confVal.forceCgoLookupHost = true
73 return
76 // If any environment-specified resolver options are specified,
77 // force cgo. Note that LOCALDOMAIN can change behavior merely
78 // by being specified with the empty string.
79 _, localDomainDefined := syscall.Getenv("LOCALDOMAIN")
80 if os.Getenv("RES_OPTIONS") != "" ||
81 os.Getenv("HOSTALIASES") != "" ||
82 confVal.netCgo ||
83 localDomainDefined {
84 confVal.forceCgoLookupHost = true
85 return
88 // OpenBSD apparently lets you override the location of resolv.conf
89 // with ASR_CONFIG. If we notice that, defer to libc.
90 if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
91 confVal.forceCgoLookupHost = true
92 return
95 if runtime.GOOS != "openbsd" {
96 confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
99 confVal.resolv = dnsReadConfig("/etc/resolv.conf")
100 if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) &&
101 !os.IsPermission(confVal.resolv.err) {
102 // If we can't read the resolv.conf file, assume it
103 // had something important in it and defer to cgo.
104 // libc's resolver might then fail too, but at least
105 // it wasn't our fault.
106 confVal.forceCgoLookupHost = true
109 if _, err := os.Stat("/etc/mdns.allow"); err == nil {
110 confVal.hasMDNSAllow = true
114 // canUseCgo reports whether calling cgo functions is allowed
115 // for non-hostname lookups.
116 func (c *conf) canUseCgo() bool {
117 return c.hostLookupOrder(nil, "") == hostLookupCgo
120 // hostLookupOrder determines which strategy to use to resolve hostname.
121 // The provided Resolver is optional. nil means to not consider its options.
122 func (c *conf) hostLookupOrder(r *Resolver, hostname string) (ret hostLookupOrder) {
123 if c.dnsDebugLevel > 1 {
124 defer func() {
125 print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
128 fallbackOrder := hostLookupCgo
129 if c.netGo || r.preferGo() {
130 fallbackOrder = hostLookupFilesDNS
132 if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
133 return fallbackOrder
135 if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 {
136 // Don't deal with special form hostnames with backslashes
137 // or '%'.
138 return fallbackOrder
141 // OpenBSD is unique and doesn't use nsswitch.conf.
142 // It also doesn't support mDNS.
143 if c.goos == "openbsd" {
144 // OpenBSD's resolv.conf manpage says that a non-existent
145 // resolv.conf means "lookup" defaults to only "files",
146 // without DNS lookups.
147 if os.IsNotExist(c.resolv.err) {
148 return hostLookupFiles
150 lookup := c.resolv.lookup
151 if len(lookup) == 0 {
152 // https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5
153 // "If the lookup keyword is not used in the
154 // system's resolv.conf file then the assumed
155 // order is 'bind file'"
156 return hostLookupDNSFiles
158 if len(lookup) < 1 || len(lookup) > 2 {
159 return fallbackOrder
161 switch lookup[0] {
162 case "bind":
163 if len(lookup) == 2 {
164 if lookup[1] == "file" {
165 return hostLookupDNSFiles
167 return fallbackOrder
169 return hostLookupDNS
170 case "file":
171 if len(lookup) == 2 {
172 if lookup[1] == "bind" {
173 return hostLookupFilesDNS
175 return fallbackOrder
177 return hostLookupFiles
178 default:
179 return fallbackOrder
183 // Canonicalize the hostname by removing any trailing dot.
184 if stringsHasSuffix(hostname, ".") {
185 hostname = hostname[:len(hostname)-1]
187 if stringsHasSuffixFold(hostname, ".local") {
188 // Per RFC 6762, the ".local" TLD is special. And
189 // because Go's native resolver doesn't do mDNS or
190 // similar local resolution mechanisms, assume that
191 // libc might (via Avahi, etc) and use cgo.
192 return fallbackOrder
195 nss := c.nss
196 srcs := nss.sources["hosts"]
197 // If /etc/nsswitch.conf doesn't exist or doesn't specify any
198 // sources for "hosts", assume Go's DNS will work fine.
199 if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
200 if c.goos == "solaris" {
201 // illumos defaults to "nis [NOTFOUND=return] files"
202 return fallbackOrder
204 if c.goos == "linux" {
205 // glibc says the default is "dns [!UNAVAIL=return] files"
206 // https://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html.
207 return hostLookupDNSFiles
209 return hostLookupFilesDNS
211 if nss.err != nil {
212 // We failed to parse or open nsswitch.conf, so
213 // conservatively assume we should use cgo if it's
214 // available.
215 return fallbackOrder
218 var mdnsSource, filesSource, dnsSource bool
219 var first string
220 for _, src := range srcs {
221 if src.source == "myhostname" {
222 if isLocalhost(hostname) || isGateway(hostname) {
223 return fallbackOrder
225 hn, err := getHostname()
226 if err != nil || stringsEqualFold(hostname, hn) {
227 return fallbackOrder
229 continue
231 if src.source == "files" || src.source == "dns" {
232 if !src.standardCriteria() {
233 return fallbackOrder // non-standard; let libc deal with it.
235 if src.source == "files" {
236 filesSource = true
237 } else if src.source == "dns" {
238 dnsSource = true
240 if first == "" {
241 first = src.source
243 continue
245 if stringsHasPrefix(src.source, "mdns") {
246 // e.g. "mdns4", "mdns4_minimal"
247 // We already returned true before if it was *.local.
248 // libc wouldn't have found a hit on this anyway.
249 mdnsSource = true
250 continue
252 // Some source we don't know how to deal with.
253 return fallbackOrder
256 // We don't parse mdns.allow files. They're rare. If one
257 // exists, it might list other TLDs (besides .local) or even
258 // '*', so just let libc deal with it.
259 if mdnsSource && c.hasMDNSAllow {
260 return fallbackOrder
263 // Cases where Go can handle it without cgo and C thread
264 // overhead.
265 switch {
266 case filesSource && dnsSource:
267 if first == "files" {
268 return hostLookupFilesDNS
269 } else {
270 return hostLookupDNSFiles
272 case filesSource:
273 return hostLookupFiles
274 case dnsSource:
275 return hostLookupDNS
278 // Something weird. Let libc deal with it.
279 return fallbackOrder
282 // goDebugNetDNS parses the value of the GODEBUG "netdns" value.
283 // The netdns value can be of the form:
284 // 1 // debug level 1
285 // 2 // debug level 2
286 // cgo // use cgo for DNS lookups
287 // go // use go for DNS lookups
288 // cgo+1 // use cgo for DNS lookups + debug level 1
289 // 1+cgo // same
290 // cgo+2 // same, but debug level 2
291 // etc.
292 func goDebugNetDNS() (dnsMode string, debugLevel int) {
293 goDebug := goDebugString("netdns")
294 parsePart := func(s string) {
295 if s == "" {
296 return
298 if '0' <= s[0] && s[0] <= '9' {
299 debugLevel, _, _ = dtoi(s)
300 } else {
301 dnsMode = s
304 if i := byteIndex(goDebug, '+'); i != -1 {
305 parsePart(goDebug[:i])
306 parsePart(goDebug[i+1:])
307 return
309 parsePart(goDebug)
310 return
313 // isLocalhost reports whether h should be considered a "localhost"
314 // name for the myhostname NSS module.
315 func isLocalhost(h string) bool {
316 return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
319 // isGateway reports whether h should be considered a "gateway"
320 // name for the myhostname NSS module.
321 func isGateway(h string) bool {
322 return stringsEqualFold(h, "gateway")