...
Source file
src/net/conf.go
Documentation: net
1
2
3
4
5
6
7 package net
8
9 import (
10 "internal/bytealg"
11 "internal/godebug"
12 "os"
13 "runtime"
14 "sync"
15 "syscall"
16 )
17
18
19 type conf struct {
20
21 forceCgoLookupHost bool
22
23 netGo bool
24 netCgo bool
25
26
27 hasMDNSAllow bool
28
29 goos string
30 dnsDebugLevel int
31
32 nss *nssConf
33 resolv *dnsConfig
34 }
35
36 var (
37 confOnce sync.Once
38 confVal = &conf{goos: runtime.GOOS}
39 )
40
41
42 func systemConf() *conf {
43 confOnce.Do(initConfVal)
44 return confVal
45 }
46
47 func initConfVal() {
48 dnsMode, debugLevel := goDebugNetDNS()
49 confVal.dnsDebugLevel = debugLevel
50 confVal.netGo = netGo || dnsMode == "go"
51 confVal.netCgo = netCgo || dnsMode == "cgo"
52 if !confVal.netGo && !confVal.netCgo && (runtime.GOOS == "windows" || runtime.GOOS == "plan9") {
53
54
55
56
57
58
59
60
61 confVal.netCgo = true
62 }
63
64 if confVal.dnsDebugLevel > 0 {
65 defer func() {
66 if confVal.dnsDebugLevel > 1 {
67 println("go package net: confVal.netCgo =", confVal.netCgo, " netGo =", confVal.netGo)
68 }
69 switch {
70 case confVal.netGo:
71 if netGo {
72 println("go package net: built with netgo build tag; using Go's DNS resolver")
73 } else {
74 println("go package net: GODEBUG setting forcing use of Go's resolver")
75 }
76 case confVal.forceCgoLookupHost:
77 println("go package net: using cgo DNS resolver")
78 default:
79 println("go package net: dynamic selection of DNS resolver")
80 }
81 }()
82 }
83
84
85
86
87 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
88 confVal.forceCgoLookupHost = true
89 return
90 }
91
92 if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
93 return
94 }
95
96
97
98
99 _, localDomainDefined := syscall.Getenv("LOCALDOMAIN")
100 if os.Getenv("RES_OPTIONS") != "" ||
101 os.Getenv("HOSTALIASES") != "" ||
102 confVal.netCgo ||
103 localDomainDefined {
104 confVal.forceCgoLookupHost = true
105 return
106 }
107
108
109
110 if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
111 confVal.forceCgoLookupHost = true
112 return
113 }
114
115 if runtime.GOOS != "openbsd" {
116 confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
117 }
118
119 confVal.resolv = dnsReadConfig("/etc/resolv.conf")
120 if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) &&
121 !os.IsPermission(confVal.resolv.err) {
122
123
124
125
126 confVal.forceCgoLookupHost = true
127 }
128
129 if _, err := os.Stat("/etc/mdns.allow"); err == nil {
130 confVal.hasMDNSAllow = true
131 }
132 }
133
134
135
136 func (c *conf) canUseCgo() bool {
137 return c.hostLookupOrder(nil, "") == hostLookupCgo
138 }
139
140
141
142 func (c *conf) hostLookupOrder(r *Resolver, hostname string) (ret hostLookupOrder) {
143 if c.dnsDebugLevel > 1 {
144 defer func() {
145 print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
146 }()
147 }
148 fallbackOrder := hostLookupCgo
149 if c.netGo || r.preferGo() {
150 switch c.goos {
151 case "windows":
152
153
154
155
156 fallbackOrder = hostLookupDNS
157 default:
158 fallbackOrder = hostLookupFilesDNS
159 }
160 }
161 if c.goos == "windows" || c.goos == "plan9" {
162 return fallbackOrder
163 }
164 if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
165 return fallbackOrder
166 }
167 if bytealg.IndexByteString(hostname, '\\') != -1 || bytealg.IndexByteString(hostname, '%') != -1 {
168
169
170 return fallbackOrder
171 }
172
173
174
175 if c.goos == "openbsd" {
176
177
178
179 if os.IsNotExist(c.resolv.err) {
180 return hostLookupFiles
181 }
182 lookup := c.resolv.lookup
183 if len(lookup) == 0 {
184
185
186
187
188 return hostLookupDNSFiles
189 }
190 if len(lookup) < 1 || len(lookup) > 2 {
191 return fallbackOrder
192 }
193 switch lookup[0] {
194 case "bind":
195 if len(lookup) == 2 {
196 if lookup[1] == "file" {
197 return hostLookupDNSFiles
198 }
199 return fallbackOrder
200 }
201 return hostLookupDNS
202 case "file":
203 if len(lookup) == 2 {
204 if lookup[1] == "bind" {
205 return hostLookupFilesDNS
206 }
207 return fallbackOrder
208 }
209 return hostLookupFiles
210 default:
211 return fallbackOrder
212 }
213 }
214
215
216 if stringsHasSuffix(hostname, ".") {
217 hostname = hostname[:len(hostname)-1]
218 }
219 if stringsHasSuffixFold(hostname, ".local") {
220
221
222
223
224 return fallbackOrder
225 }
226
227 nss := c.nss
228 srcs := nss.sources["hosts"]
229
230
231 if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
232 if c.goos == "solaris" {
233
234 return fallbackOrder
235 }
236 return hostLookupFilesDNS
237 }
238 if nss.err != nil {
239
240
241
242 return fallbackOrder
243 }
244
245 var mdnsSource, filesSource, dnsSource bool
246 var first string
247 for _, src := range srcs {
248 if src.source == "myhostname" {
249 if isLocalhost(hostname) || isGateway(hostname) {
250 return fallbackOrder
251 }
252 hn, err := getHostname()
253 if err != nil || stringsEqualFold(hostname, hn) {
254 return fallbackOrder
255 }
256 continue
257 }
258 if src.source == "files" || src.source == "dns" {
259 if !src.standardCriteria() {
260 return fallbackOrder
261 }
262 if src.source == "files" {
263 filesSource = true
264 } else if src.source == "dns" {
265 dnsSource = true
266 }
267 if first == "" {
268 first = src.source
269 }
270 continue
271 }
272 if stringsHasPrefix(src.source, "mdns") {
273
274
275
276 mdnsSource = true
277 continue
278 }
279
280 return fallbackOrder
281 }
282
283
284
285
286 if mdnsSource && c.hasMDNSAllow {
287 return fallbackOrder
288 }
289
290
291
292 switch {
293 case filesSource && dnsSource:
294 if first == "files" {
295 return hostLookupFilesDNS
296 } else {
297 return hostLookupDNSFiles
298 }
299 case filesSource:
300 return hostLookupFiles
301 case dnsSource:
302 return hostLookupDNS
303 }
304
305
306 return fallbackOrder
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321 func goDebugNetDNS() (dnsMode string, debugLevel int) {
322 goDebug := godebug.Get("netdns")
323 parsePart := func(s string) {
324 if s == "" {
325 return
326 }
327 if '0' <= s[0] && s[0] <= '9' {
328 debugLevel, _, _ = dtoi(s)
329 } else {
330 dnsMode = s
331 }
332 }
333 if i := bytealg.IndexByteString(goDebug, '+'); i != -1 {
334 parsePart(goDebug[:i])
335 parsePart(goDebug[i+1:])
336 return
337 }
338 parsePart(goDebug)
339 return
340 }
341
342
343
344 func isLocalhost(h string) bool {
345 return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
346 }
347
348
349
350 func isGateway(h string) bool {
351 return stringsEqualFold(h, "gateway")
352 }
353
View as plain text