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