* gcc-interface/decl.c (warn_on_field_placement): Issue the warning
[official-gcc.git] / libgo / go / net / dnsconfig_unix.go
blob24487af33b5f1240c38e4cf0e802922e36d55414
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.
5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
7 // Read system DNS config from /etc/resolv.conf
9 package net
11 import (
12 "os"
13 "sync/atomic"
14 "time"
17 var (
18 defaultNS = []string{"127.0.0.1:53", "[::1]:53"}
19 getHostname = os.Hostname // variable for testing
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
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,
43 file, err := open(filename)
44 if err != nil {
45 conf.servers = defaultNS
46 conf.search = dnsDefaultSearch()
47 conf.err = err
48 return conf
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
59 for line, ok := file.readLine(); ok; line, ok = file.readLine() {
60 if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
61 // comment.
62 continue
64 f := getFields(line)
65 if len(f) < 1 {
66 continue
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"))
81 case "domain": // set search path to just this domain
82 if len(f) > 1 {
83 conf.search = []string{ensureRooted(f[1])}
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])
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
102 conf.ndots = n
103 case hasPrefix(s, "timeout:"):
104 n, _, _ := dtoi(s[8:])
105 if n < 1 {
106 n = 1
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
114 conf.attempts = n
115 case s == "rotate":
116 conf.rotate = true
117 default:
118 conf.unknownOpt = true
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:]
128 default:
129 conf.unknownOpt = true
132 if len(conf.servers) == 0 {
133 conf.servers = defaultNS
135 if len(conf.search) == 0 {
136 conf.search = dnsDefaultSearch()
138 return conf
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
149 return 0
152 func dnsDefaultSearch() []string {
153 hn, err := getHostname()
154 if err != nil {
155 // best effort
156 return nil
158 if i := byteIndex(hn, '.'); i >= 0 && i < len(hn)-1 {
159 return []string{ensureRooted(hn[i+1:])}
161 return nil
164 func hasPrefix(s, prefix string) bool {
165 return len(s) >= len(prefix) && s[:len(prefix)] == prefix
168 func ensureRooted(s string) string {
169 if len(s) > 0 && s[len(s)-1] == '.' {
170 return s
172 return s + "."