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