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