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