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