Source file
src/net/conf.go
1
2
3
4
5 package net
6
7 import (
8 "errors"
9 "internal/bytealg"
10 "internal/godebug"
11 "io/fs"
12 "os"
13 "runtime"
14 "sync"
15 "syscall"
16 )
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 type conf struct {
52 netGo bool
53 netCgo bool
54
55 dnsDebugLevel int
56
57 preferCgo bool
58
59 goos string
60 mdnsTest mdnsTest
61 }
62
63
64 type mdnsTest int
65
66 const (
67 mdnsFromSystem mdnsTest = iota
68 mdnsAssumeExists
69 mdnsAssumeDoesNotExist
70 )
71
72 var (
73 confOnce sync.Once
74 confVal = &conf{goos: runtime.GOOS}
75 )
76
77
78 func systemConf() *conf {
79 confOnce.Do(initConfVal)
80 return confVal
81 }
82
83
84
85 func initConfVal() {
86 dnsMode, debugLevel := goDebugNetDNS()
87 confVal.netGo = netGoBuildTag || dnsMode == "go"
88 confVal.netCgo = netCgoBuildTag || dnsMode == "cgo"
89 confVal.dnsDebugLevel = debugLevel
90
91 if confVal.dnsDebugLevel > 0 {
92 defer func() {
93 if confVal.dnsDebugLevel > 1 {
94 println("go package net: confVal.netCgo =", confVal.netCgo, " netGo =", confVal.netGo)
95 }
96 switch {
97 case confVal.netGo:
98 if netGoBuildTag {
99 println("go package net: built with netgo build tag; using Go's DNS resolver")
100 } else {
101 println("go package net: GODEBUG setting forcing use of Go's resolver")
102 }
103 case !cgoAvailable:
104 println("go package net: cgo resolver not supported; using Go's DNS resolver")
105 case confVal.netCgo || confVal.preferCgo:
106 println("go package net: using cgo DNS resolver")
107 default:
108 println("go package net: dynamic selection of DNS resolver")
109 }
110 }()
111 }
112
113
114
115
116
117 confVal.preferCgo = false
118
119
120 if !cgoAvailable {
121 return
122 }
123
124
125 if goosPrefersCgo() {
126 confVal.preferCgo = true
127 return
128 }
129
130
131 switch runtime.GOOS {
132 case "plan9", "windows", "js", "wasip1":
133 return
134 }
135
136
137
138
139
140 _, localDomainDefined := syscall.Getenv("LOCALDOMAIN")
141 if localDomainDefined || os.Getenv("RES_OPTIONS") != "" || os.Getenv("HOSTALIASES") != "" {
142 confVal.preferCgo = true
143 return
144 }
145
146
147
148 if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
149 confVal.preferCgo = true
150 return
151 }
152 }
153
154
155
156 func goosPrefersCgo() bool {
157 switch runtime.GOOS {
158
159
160
161
162
163
164 case "windows", "plan9":
165 return true
166
167
168
169 case "darwin", "ios":
170 return true
171
172
173
174 case "android":
175 return true
176
177 default:
178 return false
179 }
180 }
181
182
183
184
185 func (c *conf) mustUseGoResolver(r *Resolver) bool {
186 if !cgoAvailable {
187 return true
188 }
189
190 if runtime.GOOS == "plan9" {
191
192
193
194
195
196
197
198 if r == nil || r.Dial == nil {
199 return false
200 }
201 }
202
203 return c.netGo || r.preferGo()
204 }
205
206
207
208
209 func (c *conf) addrLookupOrder(r *Resolver, addr string) (ret hostLookupOrder, dnsConf *dnsConfig) {
210 if c.dnsDebugLevel > 1 {
211 defer func() {
212 print("go package net: addrLookupOrder(", addr, ") = ", ret.String(), "\n")
213 }()
214 }
215 return c.lookupOrder(r, "")
216 }
217
218
219
220
221 func (c *conf) hostLookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, dnsConf *dnsConfig) {
222 if c.dnsDebugLevel > 1 {
223 defer func() {
224 print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
225 }()
226 }
227 return c.lookupOrder(r, hostname)
228 }
229
230 func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, dnsConf *dnsConfig) {
231
232 var fallbackOrder hostLookupOrder
233
234 var canUseCgo bool
235 if c.mustUseGoResolver(r) {
236
237
238
239 fallbackOrder = hostLookupFilesDNS
240 canUseCgo = false
241 } else if c.netCgo {
242
243 return hostLookupCgo, nil
244 } else if c.preferCgo {
245
246 return hostLookupCgo, nil
247 } else {
248
249
250
251 if bytealg.IndexByteString(hostname, '\\') != -1 || bytealg.IndexByteString(hostname, '%') != -1 {
252
253
254 return hostLookupCgo, nil
255 }
256
257
258 fallbackOrder = hostLookupCgo
259 canUseCgo = true
260 }
261
262
263 switch c.goos {
264 case "windows", "plan9", "android", "ios":
265 return fallbackOrder, nil
266 }
267
268
269
270
271
272
273
274 dnsConf = getSystemDNSConfig()
275
276 if canUseCgo && dnsConf.err != nil && !errors.Is(dnsConf.err, fs.ErrNotExist) && !errors.Is(dnsConf.err, fs.ErrPermission) {
277
278 return hostLookupCgo, dnsConf
279 }
280
281 if canUseCgo && dnsConf.unknownOpt {
282
283
284 return hostLookupCgo, dnsConf
285 }
286
287
288
289 if c.goos == "openbsd" {
290
291
292
293 if errors.Is(dnsConf.err, fs.ErrNotExist) {
294 return hostLookupFiles, dnsConf
295 }
296
297 lookup := dnsConf.lookup
298 if len(lookup) == 0 {
299
300
301
302
303 return hostLookupDNSFiles, dnsConf
304 }
305 if len(lookup) < 1 || len(lookup) > 2 {
306
307 return fallbackOrder, dnsConf
308 }
309 switch lookup[0] {
310 case "bind":
311 if len(lookup) == 2 {
312 if lookup[1] == "file" {
313 return hostLookupDNSFiles, dnsConf
314 }
315
316 return fallbackOrder, dnsConf
317 }
318 return hostLookupDNS, dnsConf
319 case "file":
320 if len(lookup) == 2 {
321 if lookup[1] == "bind" {
322 return hostLookupFilesDNS, dnsConf
323 }
324
325 return fallbackOrder, dnsConf
326 }
327 return hostLookupFiles, dnsConf
328 default:
329
330 return fallbackOrder, dnsConf
331 }
332
333
334
335 }
336
337
338 if stringsHasSuffix(hostname, ".") {
339 hostname = hostname[:len(hostname)-1]
340 }
341
342 nss := getSystemNSS()
343 srcs := nss.sources["hosts"]
344
345
346 if errors.Is(nss.err, fs.ErrNotExist) || (nss.err == nil && len(srcs) == 0) {
347 if canUseCgo && c.goos == "solaris" {
348
349
350
351 return hostLookupCgo, dnsConf
352 }
353
354 return hostLookupFilesDNS, dnsConf
355 }
356 if nss.err != nil {
357
358
359 return fallbackOrder, dnsConf
360 }
361
362 var hasDNSSource bool
363 var hasDNSSourceChecked bool
364
365 var filesSource, dnsSource bool
366 var first string
367 for i, src := range srcs {
368 if src.source == "files" || src.source == "dns" {
369 if canUseCgo && !src.standardCriteria() {
370
371 return hostLookupCgo, dnsConf
372 }
373 if src.source == "files" {
374 filesSource = true
375 } else {
376 hasDNSSource = true
377 hasDNSSourceChecked = true
378 dnsSource = true
379 }
380 if first == "" {
381 first = src.source
382 }
383 continue
384 }
385
386 if canUseCgo {
387 switch {
388 case hostname != "" && src.source == "myhostname":
389
390
391 if isLocalhost(hostname) || isGateway(hostname) || isOutbound(hostname) {
392 return hostLookupCgo, dnsConf
393 }
394 hn, err := getHostname()
395 if err != nil || stringsEqualFold(hostname, hn) {
396 return hostLookupCgo, dnsConf
397 }
398 continue
399 case hostname != "" && stringsHasPrefix(src.source, "mdns"):
400 if stringsHasSuffixFold(hostname, ".local") {
401
402
403
404
405 return hostLookupCgo, dnsConf
406 }
407
408
409
410
411 var haveMDNSAllow bool
412 switch c.mdnsTest {
413 case mdnsFromSystem:
414 _, err := os.Stat("/etc/mdns.allow")
415 if err != nil && !errors.Is(err, fs.ErrNotExist) {
416
417 return hostLookupCgo, dnsConf
418 }
419 haveMDNSAllow = err == nil
420 case mdnsAssumeExists:
421 haveMDNSAllow = true
422 case mdnsAssumeDoesNotExist:
423 haveMDNSAllow = false
424 }
425 if haveMDNSAllow {
426 return hostLookupCgo, dnsConf
427 }
428 continue
429 default:
430
431 return hostLookupCgo, dnsConf
432 }
433 }
434
435 if !hasDNSSourceChecked {
436 hasDNSSourceChecked = true
437 for _, v := range srcs[i+1:] {
438 if v.source == "dns" {
439 hasDNSSource = true
440 break
441 }
442 }
443 }
444
445
446
447
448 if !hasDNSSource {
449 dnsSource = true
450 if first == "" {
451 first = "dns"
452 }
453 }
454 }
455
456
457
458 switch {
459 case filesSource && dnsSource:
460 if first == "files" {
461 return hostLookupFilesDNS, dnsConf
462 } else {
463 return hostLookupDNSFiles, dnsConf
464 }
465 case filesSource:
466 return hostLookupFiles, dnsConf
467 case dnsSource:
468 return hostLookupDNS, dnsConf
469 }
470
471
472 return fallbackOrder, dnsConf
473 }
474
475 var netdns = godebug.New("netdns")
476
477
478
479
480
481
482
483
484
485
486
487
488
489 func goDebugNetDNS() (dnsMode string, debugLevel int) {
490 goDebug := netdns.Value()
491 parsePart := func(s string) {
492 if s == "" {
493 return
494 }
495 if '0' <= s[0] && s[0] <= '9' {
496 debugLevel, _, _ = dtoi(s)
497 } else {
498 dnsMode = s
499 }
500 }
501 if i := bytealg.IndexByteString(goDebug, '+'); i != -1 {
502 parsePart(goDebug[:i])
503 parsePart(goDebug[i+1:])
504 return
505 }
506 parsePart(goDebug)
507 return
508 }
509
510
511
512 func isLocalhost(h string) bool {
513 return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
514 }
515
516
517
518 func isGateway(h string) bool {
519 return stringsEqualFold(h, "_gateway")
520 }
521
522
523
524 func isOutbound(h string) bool {
525 return stringsEqualFold(h, "_outbound")
526 }
527
View as plain text