github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/src/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 // "netgo" build tag in use (or no cgo) 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 // hostLookupOrder determines which strategy to use to resolve hostname. 116 func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) { 117 if c.dnsDebugLevel > 1 { 118 defer func() { 119 print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n") 120 }() 121 } 122 if c.netGo { 123 return hostLookupFilesDNS 124 } 125 if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" { 126 return hostLookupCgo 127 } 128 if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 { 129 // Don't deal with special form hostnames with backslashes 130 // or '%'. 131 return hostLookupCgo 132 } 133 134 // OpenBSD is unique and doesn't use nsswitch.conf. 135 // It also doesn't support mDNS. 136 if c.goos == "openbsd" { 137 // OpenBSD's resolv.conf manpage says that a non-existent 138 // resolv.conf means "lookup" defaults to only "files", 139 // without DNS lookups. 140 if os.IsNotExist(c.resolv.err) { 141 return hostLookupFiles 142 } 143 lookup := c.resolv.lookup 144 if len(lookup) == 0 { 145 // http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 146 // "If the lookup keyword is not used in the 147 // system's resolv.conf file then the assumed 148 // order is 'bind file'" 149 return hostLookupDNSFiles 150 } 151 if len(lookup) < 1 || len(lookup) > 2 { 152 return hostLookupCgo 153 } 154 switch lookup[0] { 155 case "bind": 156 if len(lookup) == 2 { 157 if lookup[1] == "file" { 158 return hostLookupDNSFiles 159 } 160 return hostLookupCgo 161 } 162 return hostLookupDNS 163 case "file": 164 if len(lookup) == 2 { 165 if lookup[1] == "bind" { 166 return hostLookupFilesDNS 167 } 168 return hostLookupCgo 169 } 170 return hostLookupFiles 171 default: 172 return hostLookupCgo 173 } 174 } 175 176 hasDot := byteIndex(hostname, '.') != -1 177 178 // Canonicalize the hostname by removing any trailing dot. 179 if stringsHasSuffix(hostname, ".") { 180 hostname = hostname[:len(hostname)-1] 181 } 182 if stringsHasSuffixFold(hostname, ".local") { 183 // Per RFC 6762, the ".local" TLD is special. And 184 // because Go's native resolver doesn't do mDNS or 185 // similar local resolution mechanisms, assume that 186 // libc might (via Avahi, etc) and use cgo. 187 return hostLookupCgo 188 } 189 190 nss := c.nss 191 srcs := nss.sources["hosts"] 192 // If /etc/nsswitch.conf doesn't exist or doesn't specify any 193 // sources for "hosts", assume Go's DNS will work fine. 194 if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) { 195 if c.goos == "solaris" { 196 // illumos defaults to "nis [NOTFOUND=return] files" 197 return hostLookupCgo 198 } 199 if c.goos == "linux" { 200 // glibc says the default is "dns [!UNAVAIL=return] files" 201 // http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html. 202 return hostLookupDNSFiles 203 } 204 return hostLookupFilesDNS 205 } 206 if nss.err != nil { 207 // We failed to parse or open nsswitch.conf, so 208 // conservatively assume we should use cgo if it's 209 // available. 210 return hostLookupCgo 211 } 212 213 var mdnsSource, filesSource, dnsSource bool 214 var first string 215 for _, src := range srcs { 216 if src.source == "myhostname" { 217 if hasDot { 218 continue 219 } 220 return hostLookupCgo 221 } 222 if src.source == "files" || src.source == "dns" { 223 if !src.standardCriteria() { 224 return hostLookupCgo // non-standard; let libc deal with it. 225 } 226 if src.source == "files" { 227 filesSource = true 228 } else if src.source == "dns" { 229 dnsSource = true 230 } 231 if first == "" { 232 first = src.source 233 } 234 continue 235 } 236 if stringsHasPrefix(src.source, "mdns") { 237 // e.g. "mdns4", "mdns4_minimal" 238 // We already returned true before if it was *.local. 239 // libc wouldn't have found a hit on this anyway. 240 mdnsSource = true 241 continue 242 } 243 // Some source we don't know how to deal with. 244 return hostLookupCgo 245 } 246 247 // We don't parse mdns.allow files. They're rare. If one 248 // exists, it might list other TLDs (besides .local) or even 249 // '*', so just let libc deal with it. 250 if mdnsSource && c.hasMDNSAllow { 251 return hostLookupCgo 252 } 253 254 // Cases where Go can handle it without cgo and C thread 255 // overhead. 256 switch { 257 case filesSource && dnsSource: 258 if first == "files" { 259 return hostLookupFilesDNS 260 } else { 261 return hostLookupDNSFiles 262 } 263 case filesSource: 264 return hostLookupFiles 265 case dnsSource: 266 return hostLookupDNS 267 } 268 269 // Something weird. Let libc deal with it. 270 return hostLookupCgo 271 } 272 273 // goDebugNetDNS parses the value of the GODEBUG "netdns" value. 274 // The netdns value can be of the form: 275 // 1 // debug level 1 276 // 2 // debug level 2 277 // cgo // use cgo for DNS lookups 278 // go // use go for DNS lookups 279 // cgo+1 // use cgo for DNS lookups + debug level 1 280 // 1+cgo // same 281 // cgo+2 // same, but debug level 2 282 // etc. 283 func goDebugNetDNS() (dnsMode string, debugLevel int) { 284 goDebug := goDebugString("netdns") 285 parsePart := func(s string) { 286 if s == "" { 287 return 288 } 289 if '0' <= s[0] && s[0] <= '9' { 290 debugLevel, _ = strconv.Atoi(s) 291 } else { 292 dnsMode = s 293 } 294 } 295 if i := byteIndex(goDebug, '+'); i != -1 { 296 parsePart(goDebug[:i]) 297 parsePart(goDebug[i+1:]) 298 return 299 } 300 parsePart(goDebug) 301 return 302 }