Source file
src/net/dnsconfig_unix_test.go
1
2
3
4
5
6
7 package net
8
9 import (
10 "errors"
11 "io/fs"
12 "os"
13 "reflect"
14 "slices"
15 "strings"
16 "testing"
17 "time"
18 )
19
20 var dnsReadConfigTests = []struct {
21 name string
22 want *dnsConfig
23 }{
24 {
25 name: "testdata/resolv.conf",
26 want: &dnsConfig{
27 servers: []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"},
28 search: []string{"localdomain."},
29 ndots: 5,
30 timeout: 10 * time.Second,
31 attempts: 3,
32 rotate: true,
33 unknownOpt: true,
34 },
35 },
36 {
37 name: "testdata/domain-resolv.conf",
38 want: &dnsConfig{
39 servers: []string{"8.8.8.8:53"},
40 search: []string{"localdomain."},
41 ndots: 1,
42 timeout: 5 * time.Second,
43 attempts: 2,
44 },
45 },
46 {
47 name: "testdata/search-resolv.conf",
48 want: &dnsConfig{
49 servers: []string{"8.8.8.8:53"},
50 search: []string{"test.", "invalid."},
51 ndots: 1,
52 timeout: 5 * time.Second,
53 attempts: 2,
54 },
55 },
56 {
57 name: "testdata/search-single-dot-resolv.conf",
58 want: &dnsConfig{
59 servers: []string{"8.8.8.8:53"},
60 search: []string{},
61 ndots: 1,
62 timeout: 5 * time.Second,
63 attempts: 2,
64 },
65 },
66 {
67 name: "testdata/empty-resolv.conf",
68 want: &dnsConfig{
69 servers: defaultNS,
70 ndots: 1,
71 timeout: 5 * time.Second,
72 attempts: 2,
73 search: []string{"domain.local."},
74 },
75 },
76 {
77 name: "testdata/invalid-ndots-resolv.conf",
78 want: &dnsConfig{
79 servers: defaultNS,
80 ndots: 0,
81 timeout: 5 * time.Second,
82 attempts: 2,
83 search: []string{"domain.local."},
84 },
85 },
86 {
87 name: "testdata/large-ndots-resolv.conf",
88 want: &dnsConfig{
89 servers: defaultNS,
90 ndots: 15,
91 timeout: 5 * time.Second,
92 attempts: 2,
93 search: []string{"domain.local."},
94 },
95 },
96 {
97 name: "testdata/negative-ndots-resolv.conf",
98 want: &dnsConfig{
99 servers: defaultNS,
100 ndots: 0,
101 timeout: 5 * time.Second,
102 attempts: 2,
103 search: []string{"domain.local."},
104 },
105 },
106 {
107 name: "testdata/openbsd-resolv.conf",
108 want: &dnsConfig{
109 ndots: 1,
110 timeout: 5 * time.Second,
111 attempts: 2,
112 lookup: []string{"file", "bind"},
113 servers: []string{"169.254.169.254:53", "10.240.0.1:53"},
114 search: []string{"c.symbolic-datum-552.internal."},
115 },
116 },
117 {
118 name: "testdata/single-request-resolv.conf",
119 want: &dnsConfig{
120 servers: defaultNS,
121 ndots: 1,
122 singleRequest: true,
123 timeout: 5 * time.Second,
124 attempts: 2,
125 search: []string{"domain.local."},
126 },
127 },
128 {
129 name: "testdata/single-request-reopen-resolv.conf",
130 want: &dnsConfig{
131 servers: defaultNS,
132 ndots: 1,
133 singleRequest: true,
134 timeout: 5 * time.Second,
135 attempts: 2,
136 search: []string{"domain.local."},
137 },
138 },
139 {
140 name: "testdata/linux-use-vc-resolv.conf",
141 want: &dnsConfig{
142 servers: defaultNS,
143 ndots: 1,
144 useTCP: true,
145 timeout: 5 * time.Second,
146 attempts: 2,
147 search: []string{"domain.local."},
148 },
149 },
150 {
151 name: "testdata/freebsd-usevc-resolv.conf",
152 want: &dnsConfig{
153 servers: defaultNS,
154 ndots: 1,
155 useTCP: true,
156 timeout: 5 * time.Second,
157 attempts: 2,
158 search: []string{"domain.local."},
159 },
160 },
161 {
162 name: "testdata/openbsd-tcp-resolv.conf",
163 want: &dnsConfig{
164 servers: defaultNS,
165 ndots: 1,
166 useTCP: true,
167 timeout: 5 * time.Second,
168 attempts: 2,
169 search: []string{"domain.local."},
170 },
171 },
172 }
173
174 func TestDNSReadConfig(t *testing.T) {
175 origGetHostname := getHostname
176 defer func() { getHostname = origGetHostname }()
177 getHostname = func() (string, error) { return "host.domain.local", nil }
178
179 for _, tt := range dnsReadConfigTests {
180 want := *tt.want
181 if len(want.search) == 0 {
182 want.search = dnsDefaultSearch()
183 }
184 conf := dnsReadConfig(tt.name)
185 if conf.err != nil {
186 t.Fatal(conf.err)
187 }
188 conf.mtime = time.Time{}
189 if !reflect.DeepEqual(conf, &want) {
190 t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, want)
191 }
192 }
193 }
194
195 func TestDNSReadMissingFile(t *testing.T) {
196 origGetHostname := getHostname
197 defer func() { getHostname = origGetHostname }()
198 getHostname = func() (string, error) { return "host.domain.local", nil }
199
200 conf := dnsReadConfig("a-nonexistent-file")
201 if !os.IsNotExist(conf.err) {
202 t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, fs.ErrNotExist)
203 }
204 conf.err = nil
205 want := &dnsConfig{
206 servers: defaultNS,
207 ndots: 1,
208 timeout: 5 * time.Second,
209 attempts: 2,
210 search: []string{"domain.local."},
211 }
212 if !reflect.DeepEqual(conf, want) {
213 t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
214 }
215 }
216
217 var dnsDefaultSearchTests = []struct {
218 name string
219 err error
220 want []string
221 }{
222 {
223 name: "host.long.domain.local",
224 want: []string{"long.domain.local."},
225 },
226 {
227 name: "host.local",
228 want: []string{"local."},
229 },
230 {
231 name: "host",
232 want: nil,
233 },
234 {
235 name: "host.domain.local",
236 err: errors.New("errored"),
237 want: nil,
238 },
239 {
240
241
242 name: "foo.",
243 want: nil,
244 },
245 }
246
247 func TestDNSDefaultSearch(t *testing.T) {
248 origGetHostname := getHostname
249 defer func() { getHostname = origGetHostname }()
250
251 for _, tt := range dnsDefaultSearchTests {
252 getHostname = func() (string, error) { return tt.name, tt.err }
253 got := dnsDefaultSearch()
254 if !slices.Equal(got, tt.want) {
255 t.Errorf("dnsDefaultSearch with hostname %q and error %+v = %q, wanted %q", tt.name, tt.err, got, tt.want)
256 }
257 }
258 }
259
260 func TestDNSNameLength(t *testing.T) {
261 origGetHostname := getHostname
262 defer func() { getHostname = origGetHostname }()
263 getHostname = func() (string, error) { return "host.domain.local", nil }
264
265 var char63 = ""
266 for i := 0; i < 63; i++ {
267 char63 += "a"
268 }
269 longDomain := strings.Repeat(char63+".", 5) + "example"
270
271 for _, tt := range dnsReadConfigTests {
272 conf := dnsReadConfig(tt.name)
273 if conf.err != nil {
274 t.Fatal(conf.err)
275 }
276
277 suffixList := tt.want.search
278 if len(suffixList) == 0 {
279 suffixList = dnsDefaultSearch()
280 }
281
282 var shortestSuffix int
283 for _, suffix := range suffixList {
284 if shortestSuffix == 0 || len(suffix) < shortestSuffix {
285 shortestSuffix = len(suffix)
286 }
287 }
288
289
290
291 longName := longDomain[len(longDomain)-254+1+shortestSuffix:]
292 if longName[0] == '.' || longName[1] == '.' {
293 longName = "aa." + longName[3:]
294 }
295 for _, fqdn := range conf.nameList(longName) {
296 if len(fqdn) > 254 {
297 t.Errorf("got %d; want less than or equal to 254", len(fqdn))
298 }
299 }
300
301
302 unsuffixable := "a." + longName[1:]
303 unsuffixableResults := conf.nameList(unsuffixable)
304 if len(unsuffixableResults) != 1 {
305 t.Errorf("suffixed names %v; want []", unsuffixableResults[1:])
306 }
307
308
309 tooLong := "a." + longDomain
310 tooLongResults := conf.nameList(tooLong)
311 if tooLongResults != nil {
312 t.Errorf("suffixed names %v; want nil", tooLongResults)
313 }
314 }
315 }
316
View as plain text