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