Source file
src/net/dnsconfig_unix.go
1
2
3
4
5
6
7
8
9 package net
10
11 import (
12 "internal/bytealg"
13 "os"
14 "sync/atomic"
15 "time"
16 )
17
18 var (
19 defaultNS = []string{"127.0.0.1:53", "[::1]:53"}
20 getHostname = os.Hostname
21 )
22
23 type dnsConfig struct {
24 servers []string
25 search []string
26 ndots int
27 timeout time.Duration
28 attempts int
29 rotate bool
30 unknownOpt bool
31 lookup []string
32 err error
33 mtime time.Time
34 soffset uint32
35 singleRequest bool
36 useTCP bool
37 }
38
39
40 func dnsReadConfig(filename string) *dnsConfig {
41 conf := &dnsConfig{
42 ndots: 1,
43 timeout: 5 * time.Second,
44 attempts: 2,
45 }
46 file, err := open(filename)
47 if err != nil {
48 conf.servers = defaultNS
49 conf.search = dnsDefaultSearch()
50 conf.err = err
51 return conf
52 }
53 defer file.close()
54 if fi, err := file.file.Stat(); err == nil {
55 conf.mtime = fi.ModTime()
56 } else {
57 conf.servers = defaultNS
58 conf.search = dnsDefaultSearch()
59 conf.err = err
60 return conf
61 }
62 for line, ok := file.readLine(); ok; line, ok = file.readLine() {
63 if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
64
65 continue
66 }
67 f := getFields(line)
68 if len(f) < 1 {
69 continue
70 }
71 switch f[0] {
72 case "nameserver":
73 if len(f) > 1 && len(conf.servers) < 3 {
74
75
76
77 if parseIPv4(f[1]) != nil {
78 conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
79 } else if ip, _ := parseIPv6Zone(f[1]); ip != nil {
80 conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
81 }
82 }
83
84 case "domain":
85 if len(f) > 1 {
86 conf.search = []string{ensureRooted(f[1])}
87 }
88
89 case "search":
90 conf.search = make([]string, len(f)-1)
91 for i := 0; i < len(conf.search); i++ {
92 conf.search[i] = ensureRooted(f[i+1])
93 }
94
95 case "options":
96 for _, s := range f[1:] {
97 switch {
98 case hasPrefix(s, "ndots:"):
99 n, _, _ := dtoi(s[6:])
100 if n < 0 {
101 n = 0
102 } else if n > 15 {
103 n = 15
104 }
105 conf.ndots = n
106 case hasPrefix(s, "timeout:"):
107 n, _, _ := dtoi(s[8:])
108 if n < 1 {
109 n = 1
110 }
111 conf.timeout = time.Duration(n) * time.Second
112 case hasPrefix(s, "attempts:"):
113 n, _, _ := dtoi(s[9:])
114 if n < 1 {
115 n = 1
116 }
117 conf.attempts = n
118 case s == "rotate":
119 conf.rotate = true
120 case s == "single-request" || s == "single-request-reopen":
121
122
123
124
125
126 conf.singleRequest = true
127 case s == "use-vc" || s == "usevc" || s == "tcp":
128
129
130
131
132
133
134 conf.useTCP = true
135 default:
136 conf.unknownOpt = true
137 }
138 }
139
140 case "lookup":
141
142
143
144 conf.lookup = f[1:]
145
146 default:
147 conf.unknownOpt = true
148 }
149 }
150 if len(conf.servers) == 0 {
151 conf.servers = defaultNS
152 }
153 if len(conf.search) == 0 {
154 conf.search = dnsDefaultSearch()
155 }
156 return conf
157 }
158
159
160
161
162
163 func (c *dnsConfig) serverOffset() uint32 {
164 if c.rotate {
165 return atomic.AddUint32(&c.soffset, 1) - 1
166 }
167 return 0
168 }
169
170 func dnsDefaultSearch() []string {
171 hn, err := getHostname()
172 if err != nil {
173
174 return nil
175 }
176 if i := bytealg.IndexByteString(hn, '.'); i >= 0 && i < len(hn)-1 {
177 return []string{ensureRooted(hn[i+1:])}
178 }
179 return nil
180 }
181
182 func hasPrefix(s, prefix string) bool {
183 return len(s) >= len(prefix) && s[:len(prefix)] == prefix
184 }
185
186 func ensureRooted(s string) string {
187 if len(s) > 0 && s[len(s)-1] == '.' {
188 return s
189 }
190 return s + "."
191 }
192
View as plain text