// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris// Read system DNS config from /etc/resolv.confpackage netimport ()var (defaultNS = []string{"127.0.0.1:53", "[::1]:53"}getHostname = os.Hostname// variable for testing)typednsConfigstruct { servers []string// server addresses (in host:port form) to use search []string// rooted suffixes to append to local name ndots int// number of dots in name to trigger absolute lookup timeout time.Duration// wait before giving up on a query, including retries attempts int// lost packets before giving up on server rotate bool// round robin among servers unknownOpt bool// anything unknown was encountered lookup []string// OpenBSD top-level database "lookup" order err error// any error that occurs during open of resolv.conf mtime time.Time// time of resolv.conf modification soffset uint32// used by serverOffset singleRequest bool// use sequential A and AAAA queries instead of parallel queries useTCP bool// force usage of TCP for DNS resolutions}// See resolv.conf(5) on a Linux machine.func ( string) *dnsConfig { := &dnsConfig{ndots: 1,timeout: 5 * time.Second,attempts: 2, } , := open()if != nil { .servers = defaultNS .search = dnsDefaultSearch() .err = return }defer .close()if , := .file.Stat(); == nil { .mtime = .ModTime() } else { .servers = defaultNS .search = dnsDefaultSearch() .err = return }for , := .readLine(); ; , = .readLine() {iflen() > 0 && ([0] == ';' || [0] == '#') {// comment.continue } := getFields()iflen() < 1 {continue }switch [0] {case"nameserver": // add one name serveriflen() > 1 && len(.servers) < 3 { // small, but the standard limit// One more check: make sure server name is // just an IP address. Otherwise we need DNS // to look it up.ifparseIPv4([1]) != nil { .servers = append(.servers, JoinHostPort([1], "53")) } elseif , := parseIPv6Zone([1]); != nil { .servers = append(.servers, JoinHostPort([1], "53")) } }case"domain": // set search path to just this domainiflen() > 1 { .search = []string{ensureRooted([1])} }case"search": // set search path to given servers .search = make([]string, len()-1)for := 0; < len(.search); ++ { .search[] = ensureRooted([+1]) }case"options": // magic optionsfor , := range [1:] {switch {casehasPrefix(, "ndots:"): , , := dtoi([6:])if < 0 { = 0 } elseif > 15 { = 15 } .ndots = casehasPrefix(, "timeout:"): , , := dtoi([8:])if < 1 { = 1 } .timeout = time.Duration() * time.SecondcasehasPrefix(, "attempts:"): , , := dtoi([9:])if < 1 { = 1 } .attempts = case == "rotate": .rotate = truecase == "single-request" || == "single-request-reopen":// Linux option: // http://man7.org/linux/man-pages/man5/resolv.conf.5.html // "By default, glibc performs IPv4 and IPv6 lookups in parallel [...] // This option disables the behavior and makes glibc // perform the IPv6 and IPv4 requests sequentially." .singleRequest = truecase == "use-vc" || == "usevc" || == "tcp":// Linux (use-vc), FreeBSD (usevc) and OpenBSD (tcp) option: // http://man7.org/linux/man-pages/man5/resolv.conf.5.html // "Sets RES_USEVC in _res.options. // This option forces the use of TCP for DNS resolutions." // https://www.freebsd.org/cgi/man.cgi?query=resolv.conf&sektion=5&manpath=freebsd-release-ports // https://man.openbsd.org/resolv.conf.5 .useTCP = truedefault: .unknownOpt = true } }case"lookup":// OpenBSD option: // https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 // "the legal space-separated values are: bind, file, yp" .lookup = [1:]default: .unknownOpt = true } }iflen(.servers) == 0 { .servers = defaultNS }iflen(.search) == 0 { .search = dnsDefaultSearch() }return}// serverOffset returns an offset that can be used to determine// indices of servers in c.servers when making queries.// When the rotate option is enabled, this offset increases.// Otherwise it is always 0.func ( *dnsConfig) () uint32 {if .rotate {returnatomic.AddUint32(&.soffset, 1) - 1// return 0 to start }return0}func () []string { , := getHostname()if != nil {// best effortreturnnil }if := bytealg.IndexByteString(, '.'); >= 0 && < len()-1 {return []string{ensureRooted([+1:])} }returnnil}func (, string) bool {returnlen() >= len() && [:len()] == }func ( string) string {iflen() > 0 && [len()-1] == '.' {return }return + "."}