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