Source file
src/net/conf.go
1
2
3
4
5
6
7 package net
8
9 import (
10 "internal/bytealg"
11 "internal/godebug"
12 "os"
13 "runtime"
14 "sync"
15 "syscall"
16 )
17
18
19 type conf struct {
20
21 forceCgoLookupHost bool
22
23 netGo bool
24 netCgo bool
25
26
27 hasMDNSAllow bool
28
29 goos string
30 dnsDebugLevel int
31
32 nss *nssConf
33 resolv *dnsConfig
34 }
35
36 var (
37 confOnce sync.Once
38 confVal = &conf{goos: runtime.GOOS}
39 )
40
41
42 func systemConf() *conf {
43 confOnce.Do(initConfVal)
44 return confVal
45 }
46
47 func initConfVal() {
48 dnsMode, debugLevel := goDebugNetDNS()
49 confVal.dnsDebugLevel = debugLevel
50 confVal.netGo = netGo || dnsMode == "go"
51 confVal.netCgo = netCgo || dnsMode == "cgo"
52
53 if confVal.dnsDebugLevel > 0 {
54 defer func() {
55 switch {
56 case confVal.netGo:
57 if netGo {
58 println("go package net: built with netgo build tag; using Go's DNS resolver")
59 } else {
60 println("go package net: GODEBUG setting forcing use of Go's resolver")
61 }
62 case confVal.forceCgoLookupHost:
63 println("go package net: using cgo DNS resolver")
64 default:
65 println("go package net: dynamic selection of DNS resolver")
66 }
67 }()
68 }
69
70
71
72
73 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
74 confVal.forceCgoLookupHost = true
75 return
76 }
77
78
79
80
81 _, localDomainDefined := syscall.Getenv("LOCALDOMAIN")
82 if os.Getenv("RES_OPTIONS") != "" ||
83 os.Getenv("HOSTALIASES") != "" ||
84 confVal.netCgo ||
85 localDomainDefined {
86 confVal.forceCgoLookupHost = true
87 return
88 }
89
90
91
92 if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
93 confVal.forceCgoLookupHost = true
94 return
95 }
96
97 if runtime.GOOS != "openbsd" {
98 confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
99 }
100
101 confVal.resolv = dnsReadConfig("/etc/resolv.conf")
102 if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) &&
103 !os.IsPermission(confVal.resolv.err) {
104
105
106
107
108 confVal.forceCgoLookupHost = true
109 }
110
111 if _, err := os.Stat("/etc/mdns.allow"); err == nil {
112 confVal.hasMDNSAllow = true
113 }
114 }
115
116
117
118 func (c *conf) canUseCgo() bool {
119 return c.hostLookupOrder(nil, "") == hostLookupCgo
120 }
121
122
123
124 func (c *conf) hostLookupOrder(r *Resolver, hostname string) (ret hostLookupOrder) {
125 if c.dnsDebugLevel > 1 {
126 defer func() {
127 print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
128 }()
129 }
130 fallbackOrder := hostLookupCgo
131 if c.netGo || r.preferGo() {
132 fallbackOrder = hostLookupFilesDNS
133 }
134 if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
135 return fallbackOrder
136 }
137 if bytealg.IndexByteString(hostname, '\\') != -1 || bytealg.IndexByteString(hostname, '%') != -1 {
138
139
140 return fallbackOrder
141 }
142
143
144
145 if c.goos == "openbsd" {
146
147
148
149 if os.IsNotExist(c.resolv.err) {
150 return hostLookupFiles
151 }
152 lookup := c.resolv.lookup
153 if len(lookup) == 0 {
154
155
156
157
158 return hostLookupDNSFiles
159 }
160 if len(lookup) < 1 || len(lookup) > 2 {
161 return fallbackOrder
162 }
163 switch lookup[0] {
164 case "bind":
165 if len(lookup) == 2 {
166 if lookup[1] == "file" {
167 return hostLookupDNSFiles
168 }
169 return fallbackOrder
170 }
171 return hostLookupDNS
172 case "file":
173 if len(lookup) == 2 {
174 if lookup[1] == "bind" {
175 return hostLookupFilesDNS
176 }
177 return fallbackOrder
178 }
179 return hostLookupFiles
180 default:
181 return fallbackOrder
182 }
183 }
184
185
186 if stringsHasSuffix(hostname, ".") {
187 hostname = hostname[:len(hostname)-1]
188 }
189 if stringsHasSuffixFold(hostname, ".local") {
190
191
192
193
194 return fallbackOrder
195 }
196
197 nss := c.nss
198 srcs := nss.sources["hosts"]
199
200
201 if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
202 if c.goos == "solaris" {
203
204 return fallbackOrder
205 }
206 return hostLookupFilesDNS
207 }
208 if nss.err != nil {
209
210
211
212 return fallbackOrder
213 }
214
215 var mdnsSource, filesSource, dnsSource bool
216 var first string
217 for _, src := range srcs {
218 if src.source == "myhostname" {
219 if isLocalhost(hostname) || isGateway(hostname) {
220 return fallbackOrder
221 }
222 hn, err := getHostname()
223 if err != nil || stringsEqualFold(hostname, hn) {
224 return fallbackOrder
225 }
226 continue
227 }
228 if src.source == "files" || src.source == "dns" {
229 if !src.standardCriteria() {
230 return fallbackOrder
231 }
232 if src.source == "files" {
233 filesSource = true
234 } else if src.source == "dns" {
235 dnsSource = true
236 }
237 if first == "" {
238 first = src.source
239 }
240 continue
241 }
242 if stringsHasPrefix(src.source, "mdns") {
243
244
245
246 mdnsSource = true
247 continue
248 }
249
250 return fallbackOrder
251 }
252
253
254
255
256 if mdnsSource && c.hasMDNSAllow {
257 return fallbackOrder
258 }
259
260
261
262 switch {
263 case filesSource && dnsSource:
264 if first == "files" {
265 return hostLookupFilesDNS
266 } else {
267 return hostLookupDNSFiles
268 }
269 case filesSource:
270 return hostLookupFiles
271 case dnsSource:
272 return hostLookupDNS
273 }
274
275
276 return fallbackOrder
277 }
278
279
280
281
282
283
284
285
286
287
288
289 func goDebugNetDNS() (dnsMode string, debugLevel int) {
290 goDebug := godebug.Get("netdns")
291 parsePart := func(s string) {
292 if s == "" {
293 return
294 }
295 if '0' <= s[0] && s[0] <= '9' {
296 debugLevel, _, _ = dtoi(s)
297 } else {
298 dnsMode = s
299 }
300 }
301 if i := bytealg.IndexByteString(goDebug, '+'); i != -1 {
302 parsePart(goDebug[:i])
303 parsePart(goDebug[i+1:])
304 return
305 }
306 parsePart(goDebug)
307 return
308 }
309
310
311
312 func isLocalhost(h string) bool {
313 return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
314 }
315
316
317
318 func isGateway(h string) bool {
319 return stringsEqualFold(h, "gateway")
320 }
321
View as plain text