github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/src/net/dnsconfig_unix.go (about) 1 // Copyright 2009 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 // Read system DNS config from /etc/resolv.conf 8 9 package net 10 11 import ( 12 "os" 13 "sync/atomic" 14 "time" 15 ) 16 17 var ( 18 defaultNS = []string{"127.0.0.1:53", "[::1]:53"} 19 getHostname = os.Hostname // variable for testing 20 ) 21 22 type dnsConfig struct { 23 servers []string // server addresses (in host:port form) to use 24 search []string // rooted suffixes to append to local name 25 ndots int // number of dots in name to trigger absolute lookup 26 timeout time.Duration // wait before giving up on a query, including retries 27 attempts int // lost packets before giving up on server 28 rotate bool // round robin among servers 29 unknownOpt bool // anything unknown was encountered 30 lookup []string // OpenBSD top-level database "lookup" order 31 err error // any error that occurs during open of resolv.conf 32 mtime time.Time // time of resolv.conf modification 33 soffset uint32 // used by serverOffset 34 } 35 36 // See resolv.conf(5) on a Linux machine. 37 func dnsReadConfig(filename string) *dnsConfig { 38 conf := &dnsConfig{ 39 ndots: 1, 40 timeout: 5 * time.Second, 41 attempts: 2, 42 } 43 file, err := open(filename) 44 if err != nil { 45 conf.servers = defaultNS 46 conf.search = dnsDefaultSearch() 47 conf.err = err 48 return conf 49 } 50 defer file.close() 51 if fi, err := file.file.Stat(); err == nil { 52 conf.mtime = fi.ModTime() 53 } else { 54 conf.servers = defaultNS 55 conf.search = dnsDefaultSearch() 56 conf.err = err 57 return conf 58 } 59 for line, ok := file.readLine(); ok; line, ok = file.readLine() { 60 if len(line) > 0 && (line[0] == ';' || line[0] == '#') { 61 // comment. 62 continue 63 } 64 f := getFields(line) 65 if len(f) < 1 { 66 continue 67 } 68 switch f[0] { 69 case "nameserver": // add one name server 70 if len(f) > 1 && len(conf.servers) < 3 { // small, but the standard limit 71 // One more check: make sure server name is 72 // just an IP address. Otherwise we need DNS 73 // to look it up. 74 if parseIPv4(f[1]) != nil { 75 conf.servers = append(conf.servers, JoinHostPort(f[1], "53")) 76 } else if ip, _ := parseIPv6(f[1], true); ip != nil { 77 conf.servers = append(conf.servers, JoinHostPort(f[1], "53")) 78 } 79 } 80 81 case "domain": // set search path to just this domain 82 if len(f) > 1 { 83 conf.search = []string{ensureRooted(f[1])} 84 } 85 86 case "search": // set search path to given servers 87 conf.search = make([]string, len(f)-1) 88 for i := 0; i < len(conf.search); i++ { 89 conf.search[i] = ensureRooted(f[i+1]) 90 } 91 92 case "options": // magic options 93 for _, s := range f[1:] { 94 switch { 95 case hasPrefix(s, "ndots:"): 96 n, _, _ := dtoi(s[6:]) 97 if n < 0 { 98 n = 0 99 } else if n > 15 { 100 n = 15 101 } 102 conf.ndots = n 103 case hasPrefix(s, "timeout:"): 104 n, _, _ := dtoi(s[8:]) 105 if n < 1 { 106 n = 1 107 } 108 conf.timeout = time.Duration(n) * time.Second 109 case hasPrefix(s, "attempts:"): 110 n, _, _ := dtoi(s[9:]) 111 if n < 1 { 112 n = 1 113 } 114 conf.attempts = n 115 case s == "rotate": 116 conf.rotate = true 117 default: 118 conf.unknownOpt = true 119 } 120 } 121 122 case "lookup": 123 // OpenBSD option: 124 // http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 125 // "the legal space-separated values are: bind, file, yp" 126 conf.lookup = f[1:] 127 128 default: 129 conf.unknownOpt = true 130 } 131 } 132 if len(conf.servers) == 0 { 133 conf.servers = defaultNS 134 } 135 if len(conf.search) == 0 { 136 conf.search = dnsDefaultSearch() 137 } 138 return conf 139 } 140 141 // serverOffset returns an offset that can be used to determine 142 // indices of servers in c.servers when making queries. 143 // When the rotate option is enabled, this offset increases. 144 // Otherwise it is always 0. 145 func (c *dnsConfig) serverOffset() uint32 { 146 if c.rotate { 147 return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start 148 } 149 return 0 150 } 151 152 func dnsDefaultSearch() []string { 153 hn, err := getHostname() 154 if err != nil { 155 // best effort 156 return nil 157 } 158 if i := byteIndex(hn, '.'); i >= 0 && i < len(hn)-1 { 159 return []string{ensureRooted(hn[i+1:])} 160 } 161 return nil 162 } 163 164 func hasPrefix(s, prefix string) bool { 165 return len(s) >= len(prefix) && s[:len(prefix)] == prefix 166 } 167 168 func ensureRooted(s string) string { 169 if len(s) > 0 && s[len(s)-1] == '.' { 170 return s 171 } 172 return s + "." 173 }