github.com/zxy12/golang151_with_comment@v0.0.0-20190507085033-721809559d3c/net/conf.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package net 8 9 import ( 10 "os" 11 "runtime" 12 "strconv" 13 "sync" 14 "syscall" 15 ) 16 17 // conf represents a system's network configuration. 18 type conf struct { 19 // forceCgoLookupHost forces CGO to always be used, if available. 20 forceCgoLookupHost bool 21 22 netGo bool // go DNS resolution forced 23 netCgo bool // cgo DNS resolution forced 24 25 // machine has an /etc/mdns.allow file 26 hasMDNSAllow bool 27 28 goos string // the runtime.GOOS, to ease testing 29 dnsDebugLevel int 30 31 nss *nssConf 32 resolv *dnsConfig 33 } 34 35 var ( 36 confOnce sync.Once // guards init of confVal via initConfVal 37 confVal = &conf{goos: runtime.GOOS} 38 ) 39 40 // systemConf returns the machine's network configuration. 41 func systemConf() *conf { 42 confOnce.Do(initConfVal) 43 return confVal 44 } 45 46 func initConfVal() { 47 dnsMode, debugLevel := goDebugNetDNS() 48 confVal.dnsDebugLevel = debugLevel 49 confVal.netGo = netGo || dnsMode == "go" 50 confVal.netCgo = netCgo || dnsMode == "cgo" 51 52 if confVal.dnsDebugLevel > 0 { 53 defer func() { 54 switch { 55 case confVal.netGo: 56 if netGo { 57 println("go package net: built with netgo build tag; using Go's DNS resolver") 58 } else { 59 println("go package net: GODEBUG setting forcing use of Go's resolver") 60 } 61 case confVal.forceCgoLookupHost: 62 println("go package net: using cgo DNS resolver") 63 default: 64 println("go package net: dynamic selection of DNS resolver") 65 } 66 }() 67 } 68 69 // Darwin pops up annoying dialog boxes if programs try to do 70 // their own DNS requests. So always use cgo instead, which 71 // avoids that. 72 if runtime.GOOS == "darwin" { 73 confVal.forceCgoLookupHost = true 74 return 75 } 76 77 // If any environment-specified resolver options are specified, 78 // force cgo. Note that LOCALDOMAIN can change behavior merely 79 // by being specified with the empty string. 80 _, localDomainDefined := syscall.Getenv("LOCALDOMAIN") 81 if os.Getenv("RES_OPTIONS") != "" || 82 os.Getenv("HOSTALIASES") != "" || 83 confVal.netCgo || 84 localDomainDefined { 85 confVal.forceCgoLookupHost = true 86 return 87 } 88 89 // OpenBSD apparently lets you override the location of resolv.conf 90 // with ASR_CONFIG. If we notice that, defer to libc. 91 if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" { 92 confVal.forceCgoLookupHost = true 93 return 94 } 95 96 if runtime.GOOS != "openbsd" { 97 confVal.nss = parseNSSConfFile("/etc/nsswitch.conf") 98 } 99 100 confVal.resolv = dnsReadConfig("/etc/resolv.conf") 101 if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) && 102 !os.IsPermission(confVal.resolv.err) { 103 // If we can't read the resolv.conf file, assume it 104 // had something important in it and defer to cgo. 105 // libc's resolver might then fail too, but at least 106 // it wasn't our fault. 107 confVal.forceCgoLookupHost = true 108 } 109 110 if _, err := os.Stat("/etc/mdns.allow"); err == nil { 111 confVal.hasMDNSAllow = true 112 } 113 } 114 115 // canUseCgo reports whether calling cgo functions is allowed 116 // for non-hostname lookups. 117 func (c *conf) canUseCgo() bool { 118 return c.hostLookupOrder("") == hostLookupCgo 119 } 120 121 // hostLookupOrder determines which strategy to use to resolve hostname. 122 func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) { 123 if c.dnsDebugLevel > 1 { 124 defer func() { 125 print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n") 126 }() 127 } 128 if c.netGo { 129 return hostLookupFilesDNS 130 } 131 if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" { 132 return hostLookupCgo 133 } 134 if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 { 135 // Don't deal with special form hostnames with backslashes 136 // or '%'. 137 return hostLookupCgo 138 } 139 140 // OpenBSD is unique and doesn't use nsswitch.conf. 141 // It also doesn't support mDNS. 142 if c.goos == "openbsd" { 143 // OpenBSD's resolv.conf manpage says that a non-existent 144 // resolv.conf means "lookup" defaults to only "files", 145 // without DNS lookups. 146 if os.IsNotExist(c.resolv.err) { 147 return hostLookupFiles 148 } 149 lookup := c.resolv.lookup 150 if len(lookup) == 0 { 151 // http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 152 // "If the lookup keyword is not used in the 153 // system's resolv.conf file then the assumed 154 // order is 'bind file'" 155 return hostLookupDNSFiles 156 } 157 if len(lookup) < 1 || len(lookup) > 2 { 158 return hostLookupCgo 159 } 160 switch lookup[0] { 161 case "bind": 162 if len(lookup) == 2 { 163 if lookup[1] == "file" { 164 return hostLookupDNSFiles 165 } 166 return hostLookupCgo 167 } 168 return hostLookupDNS 169 case "file": 170 if len(lookup) == 2 { 171 if lookup[1] == "bind" { 172 return hostLookupFilesDNS 173 } 174 return hostLookupCgo 175 } 176 return hostLookupFiles 177 default: 178 return hostLookupCgo 179 } 180 } 181 182 hasDot := byteIndex(hostname, '.') != -1 183 184 // Canonicalize the hostname by removing any trailing dot. 185 if stringsHasSuffix(hostname, ".") { 186 hostname = hostname[:len(hostname)-1] 187 } 188 if stringsHasSuffixFold(hostname, ".local") { 189 // Per RFC 6762, the ".local" TLD is special. And 190 // because Go's native resolver doesn't do mDNS or 191 // similar local resolution mechanisms, assume that 192 // libc might (via Avahi, etc) and use cgo. 193 return hostLookupCgo 194 } 195 196 nss := c.nss 197 srcs := nss.sources["hosts"] 198 // If /etc/nsswitch.conf doesn't exist or doesn't specify any 199 // sources for "hosts", assume Go's DNS will work fine. 200 if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) { 201 if c.goos == "solaris" { 202 // illumos defaults to "nis [NOTFOUND=return] files" 203 return hostLookupCgo 204 } 205 if c.goos == "linux" { 206 // glibc says the default is "dns [!UNAVAIL=return] files" 207 // http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html. 208 return hostLookupDNSFiles 209 } 210 return hostLookupFilesDNS 211 } 212 if nss.err != nil { 213 // We failed to parse or open nsswitch.conf, so 214 // conservatively assume we should use cgo if it's 215 // available. 216 return hostLookupCgo 217 } 218 219 var mdnsSource, filesSource, dnsSource bool 220 var first string 221 for _, src := range srcs { 222 if src.source == "myhostname" { 223 if hasDot { 224 continue 225 } 226 return hostLookupCgo 227 } 228 if src.source == "files" || src.source == "dns" { 229 if !src.standardCriteria() { 230 return hostLookupCgo // non-standard; let libc deal with it. 231 } 232 if src.source == "files" { 233 filesSource = true 234 } else if src.source == "dns" { 235 dnsSource = true 236 } 237 if first == "" { 238 first = src.source 239 } 240 continue 241 } 242 if stringsHasPrefix(src.source, "mdns") { 243 // e.g. "mdns4", "mdns4_minimal" 244 // We already returned true before if it was *.local. 245 // libc wouldn't have found a hit on this anyway. 246 mdnsSource = true 247 continue 248 } 249 // Some source we don't know how to deal with. 250 return hostLookupCgo 251 } 252 253 // We don't parse mdns.allow files. They're rare. If one 254 // exists, it might list other TLDs (besides .local) or even 255 // '*', so just let libc deal with it. 256 if mdnsSource && c.hasMDNSAllow { 257 return hostLookupCgo 258 } 259 260 // Cases where Go can handle it without cgo and C thread 261 // overhead. 262 switch { 263 case filesSource && dnsSource: 264 if first == "files" { 265 return hostLookupFilesDNS 266 } else { 267 return hostLookupDNSFiles 268 } 269 case filesSource: 270 return hostLookupFiles 271 case dnsSource: 272 return hostLookupDNS 273 } 274 275 // Something weird. Let libc deal with it. 276 return hostLookupCgo 277 } 278 279 // goDebugNetDNS parses the value of the GODEBUG "netdns" value. 280 // The netdns value can be of the form: 281 // 1 // debug level 1 282 // 2 // debug level 2 283 // cgo // use cgo for DNS lookups 284 // go // use go for DNS lookups 285 // cgo+1 // use cgo for DNS lookups + debug level 1 286 // 1+cgo // same 287 // cgo+2 // same, but debug level 2 288 // etc. 289 func goDebugNetDNS() (dnsMode string, debugLevel int) { 290 goDebug := goDebugString("netdns") 291 parsePart := func(s string) { 292 if s == "" { 293 return 294 } 295 if '0' <= s[0] && s[0] <= '9' { 296 debugLevel, _ = strconv.Atoi(s) 297 } else { 298 dnsMode = s 299 } 300 } 301 if i := byteIndex(goDebug, '+'); i != -1 { 302 parsePart(goDebug[:i]) 303 parsePart(goDebug[i+1:]) 304 return 305 } 306 parsePart(goDebug) 307 return 308 }