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 hostname = stringslite.TrimSuffix(hostname, ".")
340
341 nss := getSystemNSS()
342 srcs := nss.sources["hosts"]
343
344
345 if errors.Is(nss.err, fs.ErrNotExist) || (nss.err == nil && len(srcs) == 0) {
346 if canUseCgo && c.goos == "solaris" {
347
348
349
350 return hostLookupCgo, dnsConf
351 }
352
353 return hostLookupFilesDNS, dnsConf
354 }
355 if nss.err != nil {
356
357
358 return fallbackOrder, dnsConf
359 }
360
361 var hasDNSSource bool
362 var hasDNSSourceChecked bool
363
364 var filesSource, dnsSource bool
365 var first string
366 for i, src := range srcs {
367 if src.source == "files" || src.source == "dns" {
368 if canUseCgo && !src.standardCriteria() {
369
370 return hostLookupCgo, dnsConf
371 }
372 if src.source == "files" {
373 filesSource = true
374 } else {
375 hasDNSSource = true
376 hasDNSSourceChecked = true
377 dnsSource = true
378 }
379 if first == "" {
380 first = src.source
381 }
382 continue
383 }
384
385 if canUseCgo {
386 switch {
387 case hostname != "" && src.source == "myhostname":
388
389
390 if isLocalhost(hostname) || isGateway(hostname) || isOutbound(hostname) {
391 return hostLookupCgo, dnsConf
392 }
393 hn, err := getHostname()
394 if err != nil || stringsEqualFold(hostname, hn) {
395 return hostLookupCgo, dnsConf
396 }
397 continue
398 case hostname != "" && stringslite.HasPrefix(src.source, "mdns"):
399 if stringsHasSuffixFold(hostname, ".local") {
400
401
402
403
404 return hostLookupCgo, dnsConf
405 }
406
407
408
409
410 var haveMDNSAllow bool
411 switch c.mdnsTest {
412 case mdnsFromSystem:
413 _, err := os.Stat("/etc/mdns.allow")
414 if err != nil && !errors.Is(err, fs.ErrNotExist) {
415
416 return hostLookupCgo, dnsConf
417 }
418 haveMDNSAllow = err == nil
419 case mdnsAssumeExists:
420 haveMDNSAllow = true
421 case mdnsAssumeDoesNotExist:
422 haveMDNSAllow = false
423 }
424 if haveMDNSAllow {
425 return hostLookupCgo, dnsConf
426 }
427 continue
428 default:
429
430 return hostLookupCgo, dnsConf
431 }
432 }
433
434 if !hasDNSSourceChecked {
435 hasDNSSourceChecked = true
436 for _, v := range srcs[i+1:] {
437 if v.source == "dns" {
438 hasDNSSource = true
439 break
440 }
441 }
442 }
443
444
445
446
447 if !hasDNSSource {
448 dnsSource = true
449 if first == "" {
450 first = "dns"
451 }
452 }
453 }
454
455
456
457 switch {
458 case filesSource && dnsSource:
459 if first == "files" {
460 return hostLookupFilesDNS, dnsConf
461 } else {
462 return hostLookupDNSFiles, dnsConf
463 }
464 case filesSource:
465 return hostLookupFiles, dnsConf
466 case dnsSource:
467 return hostLookupDNS, dnsConf
468 }
469
470
471 return fallbackOrder, dnsConf
472 }
473
474 var netdns = godebug.New("netdns")
475
476
477
478
479
480
481
482
483
484
485
486
487
488 func goDebugNetDNS() (dnsMode string, debugLevel int) {
489 goDebug := netdns.Value()
490 parsePart := func(s string) {
491 if s == "" {
492 return
493 }
494 if '0' <= s[0] && s[0] <= '9' {
495 debugLevel, _, _ = dtoi(s)
496 } else {
497 dnsMode = s
498 }
499 }
500 if i := bytealg.IndexByteString(goDebug, '+'); i != -1 {
501 parsePart(goDebug[:i])
502 parsePart(goDebug[i+1:])
503 return
504 }
505 parsePart(goDebug)
506 return
507 }
508
509
510
511 func isLocalhost(h string) bool {
512 return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
513 }
514
515
516
517 func isGateway(h string) bool {
518 return stringsEqualFold(h, "_gateway")
519 }
520
521
522
523 func isOutbound(h string) bool {
524 return stringsEqualFold(h, "_outbound")
525 }
526
View as plain text