1// Copyright 2015 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 5//go:build unix 6 7package net 8 9import ( 10 "io/fs" 11 "os" 12 "testing" 13 "time" 14) 15 16type nssHostTest struct { 17 host string 18 localhost string 19 want hostLookupOrder 20} 21 22func nssStr(t *testing.T, s string) *nssConf { 23 f, err := os.CreateTemp(t.TempDir(), "nss") 24 if err != nil { 25 t.Fatal(err) 26 } 27 if _, err := f.WriteString(s); err != nil { 28 t.Fatal(err) 29 } 30 if err := f.Close(); err != nil { 31 t.Fatal(err) 32 } 33 return parseNSSConfFile(f.Name()) 34} 35 36// represents a dnsConfig returned by parsing a nonexistent resolv.conf 37var defaultResolvConf = &dnsConfig{ 38 servers: defaultNS, 39 ndots: 1, 40 timeout: 5, 41 attempts: 2, 42 err: fs.ErrNotExist, 43} 44 45func TestConfHostLookupOrder(t *testing.T) { 46 // These tests are written for a system with cgo available, 47 // without using the netgo tag. 48 if netGoBuildTag { 49 t.Skip("skipping test because net package built with netgo tag") 50 } 51 if !cgoAvailable { 52 t.Skip("skipping test because cgo resolver not available") 53 } 54 55 tests := []struct { 56 name string 57 c *conf 58 nss *nssConf 59 resolver *Resolver 60 resolv *dnsConfig 61 hostTests []nssHostTest 62 }{ 63 { 64 name: "force", 65 c: &conf{ 66 preferCgo: true, 67 netCgo: true, 68 }, 69 resolv: defaultResolvConf, 70 nss: nssStr(t, "foo: bar"), 71 hostTests: []nssHostTest{ 72 {"foo.local", "myhostname", hostLookupCgo}, 73 {"google.com", "myhostname", hostLookupCgo}, 74 }, 75 }, 76 { 77 name: "netgo_dns_before_files", 78 c: &conf{ 79 netGo: true, 80 }, 81 resolv: defaultResolvConf, 82 nss: nssStr(t, "hosts: dns files"), 83 hostTests: []nssHostTest{ 84 {"x.com", "myhostname", hostLookupDNSFiles}, 85 }, 86 }, 87 { 88 name: "netgo_fallback_on_cgo", 89 c: &conf{ 90 netGo: true, 91 }, 92 resolv: defaultResolvConf, 93 nss: nssStr(t, "hosts: dns files something_custom"), 94 hostTests: []nssHostTest{ 95 {"x.com", "myhostname", hostLookupDNSFiles}, 96 }, 97 }, 98 { 99 name: "ubuntu_trusty_avahi", 100 c: &conf{ 101 mdnsTest: mdnsAssumeDoesNotExist, 102 }, 103 resolv: defaultResolvConf, 104 nss: nssStr(t, "hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"), 105 hostTests: []nssHostTest{ 106 {"foo.local", "myhostname", hostLookupCgo}, 107 {"foo.local.", "myhostname", hostLookupCgo}, 108 {"foo.LOCAL", "myhostname", hostLookupCgo}, 109 {"foo.LOCAL.", "myhostname", hostLookupCgo}, 110 {"google.com", "myhostname", hostLookupFilesDNS}, 111 }, 112 }, 113 { 114 name: "freebsdlinux_no_resolv_conf", 115 c: &conf{ 116 goos: "freebsd", 117 }, 118 resolv: defaultResolvConf, 119 nss: nssStr(t, "foo: bar"), 120 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}}, 121 }, 122 // On OpenBSD, no resolv.conf means no DNS. 123 { 124 name: "openbsd_no_resolv_conf", 125 c: &conf{ 126 goos: "openbsd", 127 }, 128 resolv: defaultResolvConf, 129 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}}, 130 }, 131 { 132 name: "solaris_no_nsswitch", 133 c: &conf{ 134 goos: "solaris", 135 }, 136 resolv: defaultResolvConf, 137 nss: &nssConf{err: fs.ErrNotExist}, 138 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}}, 139 }, 140 { 141 name: "openbsd_lookup_bind_file", 142 c: &conf{ 143 goos: "openbsd", 144 }, 145 resolv: &dnsConfig{lookup: []string{"bind", "file"}}, 146 hostTests: []nssHostTest{ 147 {"google.com", "myhostname", hostLookupDNSFiles}, 148 {"foo.local", "myhostname", hostLookupDNSFiles}, 149 }, 150 }, 151 { 152 name: "openbsd_lookup_file_bind", 153 c: &conf{ 154 goos: "openbsd", 155 }, 156 resolv: &dnsConfig{lookup: []string{"file", "bind"}}, 157 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}}, 158 }, 159 { 160 name: "openbsd_lookup_bind", 161 c: &conf{ 162 goos: "openbsd", 163 }, 164 resolv: &dnsConfig{lookup: []string{"bind"}}, 165 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNS}}, 166 }, 167 { 168 name: "openbsd_lookup_file", 169 c: &conf{ 170 goos: "openbsd", 171 }, 172 resolv: &dnsConfig{lookup: []string{"file"}}, 173 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}}, 174 }, 175 { 176 name: "openbsd_lookup_yp", 177 c: &conf{ 178 goos: "openbsd", 179 }, 180 resolv: &dnsConfig{lookup: []string{"file", "bind", "yp"}}, 181 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}}, 182 }, 183 { 184 name: "openbsd_lookup_two", 185 c: &conf{ 186 goos: "openbsd", 187 }, 188 resolv: &dnsConfig{lookup: []string{"file", "foo"}}, 189 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}}, 190 }, 191 { 192 name: "openbsd_lookup_empty", 193 c: &conf{ 194 goos: "openbsd", 195 }, 196 resolv: &dnsConfig{lookup: nil}, 197 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}}, 198 }, 199 { 200 name: "linux_no_nsswitch.conf", 201 c: &conf{ 202 goos: "linux", 203 }, 204 resolv: defaultResolvConf, 205 nss: &nssConf{err: fs.ErrNotExist}, 206 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}}, 207 }, 208 { 209 name: "linux_empty_nsswitch.conf", 210 c: &conf{ 211 goos: "linux", 212 }, 213 resolv: defaultResolvConf, 214 nss: nssStr(t, ""), 215 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}}, 216 }, 217 { 218 name: "files_mdns_dns", 219 c: &conf{ 220 mdnsTest: mdnsAssumeDoesNotExist, 221 }, 222 resolv: defaultResolvConf, 223 nss: nssStr(t, "hosts: files mdns dns"), 224 hostTests: []nssHostTest{ 225 {"x.com", "myhostname", hostLookupFilesDNS}, 226 {"x.local", "myhostname", hostLookupCgo}, 227 }, 228 }, 229 { 230 name: "dns_special_hostnames", 231 c: &conf{}, 232 resolv: defaultResolvConf, 233 nss: nssStr(t, "hosts: dns"), 234 hostTests: []nssHostTest{ 235 {"x.com", "myhostname", hostLookupDNS}, 236 {"x\\.com", "myhostname", hostLookupCgo}, // punt on weird glibc escape 237 {"foo.com%en0", "myhostname", hostLookupCgo}, // and IPv6 zones 238 }, 239 }, 240 { 241 name: "mdns_allow", 242 c: &conf{ 243 mdnsTest: mdnsAssumeExists, 244 }, 245 resolv: defaultResolvConf, 246 nss: nssStr(t, "hosts: files mdns dns"), 247 hostTests: []nssHostTest{ 248 {"x.com", "myhostname", hostLookupCgo}, 249 {"x.local", "myhostname", hostLookupCgo}, 250 }, 251 }, 252 { 253 name: "files_dns", 254 c: &conf{}, 255 resolv: defaultResolvConf, 256 nss: nssStr(t, "hosts: files dns"), 257 hostTests: []nssHostTest{ 258 {"x.com", "myhostname", hostLookupFilesDNS}, 259 {"x", "myhostname", hostLookupFilesDNS}, 260 {"x.local", "myhostname", hostLookupFilesDNS}, 261 }, 262 }, 263 { 264 name: "dns_files", 265 c: &conf{}, 266 resolv: defaultResolvConf, 267 nss: nssStr(t, "hosts: dns files"), 268 hostTests: []nssHostTest{ 269 {"x.com", "myhostname", hostLookupDNSFiles}, 270 {"x", "myhostname", hostLookupDNSFiles}, 271 {"x.local", "myhostname", hostLookupDNSFiles}, 272 }, 273 }, 274 { 275 name: "something_custom", 276 c: &conf{}, 277 resolv: defaultResolvConf, 278 nss: nssStr(t, "hosts: dns files something_custom"), 279 hostTests: []nssHostTest{ 280 {"x.com", "myhostname", hostLookupCgo}, 281 }, 282 }, 283 { 284 name: "myhostname", 285 c: &conf{}, 286 resolv: defaultResolvConf, 287 nss: nssStr(t, "hosts: files dns myhostname"), 288 hostTests: []nssHostTest{ 289 {"x.com", "myhostname", hostLookupFilesDNS}, 290 {"myhostname", "myhostname", hostLookupCgo}, 291 {"myHostname", "myhostname", hostLookupCgo}, 292 {"myhostname.dot", "myhostname.dot", hostLookupCgo}, 293 {"myHostname.dot", "myhostname.dot", hostLookupCgo}, 294 {"_gateway", "myhostname", hostLookupCgo}, 295 {"_Gateway", "myhostname", hostLookupCgo}, 296 {"_outbound", "myhostname", hostLookupCgo}, 297 {"_Outbound", "myhostname", hostLookupCgo}, 298 {"localhost", "myhostname", hostLookupCgo}, 299 {"Localhost", "myhostname", hostLookupCgo}, 300 {"anything.localhost", "myhostname", hostLookupCgo}, 301 {"Anything.localhost", "myhostname", hostLookupCgo}, 302 {"localhost.localdomain", "myhostname", hostLookupCgo}, 303 {"Localhost.Localdomain", "myhostname", hostLookupCgo}, 304 {"anything.localhost.localdomain", "myhostname", hostLookupCgo}, 305 {"Anything.Localhost.Localdomain", "myhostname", hostLookupCgo}, 306 {"somehostname", "myhostname", hostLookupFilesDNS}, 307 }, 308 }, 309 { 310 name: "ubuntu14.04.02", 311 c: &conf{ 312 mdnsTest: mdnsAssumeDoesNotExist, 313 }, 314 resolv: defaultResolvConf, 315 nss: nssStr(t, "hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4"), 316 hostTests: []nssHostTest{ 317 {"x.com", "myhostname", hostLookupFilesDNS}, 318 {"somehostname", "myhostname", hostLookupFilesDNS}, 319 {"myhostname", "myhostname", hostLookupCgo}, 320 }, 321 }, 322 // Debian Squeeze is just "dns,files", but lists all 323 // the default criteria for dns, but then has a 324 // non-standard but redundant notfound=return for the 325 // files. 326 { 327 name: "debian_squeeze", 328 c: &conf{}, 329 resolv: defaultResolvConf, 330 nss: nssStr(t, "hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]"), 331 hostTests: []nssHostTest{ 332 {"x.com", "myhostname", hostLookupDNSFiles}, 333 {"somehostname", "myhostname", hostLookupDNSFiles}, 334 }, 335 }, 336 { 337 name: "resolv.conf-unknown", 338 c: &conf{}, 339 resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true}, 340 nss: nssStr(t, "foo: bar"), 341 hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}}, 342 }, 343 // Issue 24393: make sure "Resolver.PreferGo = true" acts like netgo. 344 { 345 name: "resolver-prefergo", 346 resolver: &Resolver{PreferGo: true}, 347 c: &conf{ 348 preferCgo: true, 349 netCgo: true, 350 }, 351 resolv: defaultResolvConf, 352 nss: nssStr(t, ""), 353 hostTests: []nssHostTest{ 354 {"localhost", "myhostname", hostLookupFilesDNS}, 355 }, 356 }, 357 { 358 name: "unknown-source", 359 resolver: &Resolver{PreferGo: true}, 360 c: &conf{}, 361 resolv: defaultResolvConf, 362 nss: nssStr(t, "hosts: resolve files"), 363 hostTests: []nssHostTest{ 364 {"x.com", "myhostname", hostLookupDNSFiles}, 365 }, 366 }, 367 { 368 name: "dns-among-unknown-sources", 369 resolver: &Resolver{PreferGo: true}, 370 c: &conf{}, 371 resolv: defaultResolvConf, 372 nss: nssStr(t, "hosts: mymachines files dns"), 373 hostTests: []nssHostTest{ 374 {"x.com", "myhostname", hostLookupFilesDNS}, 375 }, 376 }, 377 { 378 name: "dns-among-unknown-sources-2", 379 resolver: &Resolver{PreferGo: true}, 380 c: &conf{}, 381 resolv: defaultResolvConf, 382 nss: nssStr(t, "hosts: dns mymachines files"), 383 hostTests: []nssHostTest{ 384 {"x.com", "myhostname", hostLookupDNSFiles}, 385 }, 386 }, 387 } 388 389 origGetHostname := getHostname 390 defer func() { getHostname = origGetHostname }() 391 defer setSystemNSS(getSystemNSS(), 0) 392 conf, err := newResolvConfTest() 393 if err != nil { 394 t.Fatal(err) 395 } 396 defer conf.teardown() 397 398 for _, tt := range tests { 399 if !conf.forceUpdateConf(tt.resolv, time.Now().Add(time.Hour)) { 400 t.Errorf("%s: failed to change resolv config", tt.name) 401 } 402 for _, ht := range tt.hostTests { 403 getHostname = func() (string, error) { return ht.localhost, nil } 404 setSystemNSS(tt.nss, time.Hour) 405 406 gotOrder, _ := tt.c.hostLookupOrder(tt.resolver, ht.host) 407 if gotOrder != ht.want { 408 t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want) 409 } 410 } 411 } 412} 413 414func TestAddrLookupOrder(t *testing.T) { 415 // This test is written for a system with cgo available, 416 // without using the netgo tag. 417 if netGoBuildTag { 418 t.Skip("skipping test because net package built with netgo tag") 419 } 420 if !cgoAvailable { 421 t.Skip("skipping test because cgo resolver not available") 422 } 423 424 defer setSystemNSS(getSystemNSS(), 0) 425 c, err := newResolvConfTest() 426 if err != nil { 427 t.Fatal(err) 428 } 429 defer c.teardown() 430 431 if !c.forceUpdateConf(defaultResolvConf, time.Now().Add(time.Hour)) { 432 t.Fatal("failed to change resolv config") 433 } 434 435 setSystemNSS(nssStr(t, "hosts: files myhostname dns"), time.Hour) 436 cnf := &conf{} 437 order, _ := cnf.addrLookupOrder(nil, "192.0.2.1") 438 if order != hostLookupCgo { 439 t.Errorf("addrLookupOrder returned: %v, want cgo", order) 440 } 441 442 setSystemNSS(nssStr(t, "hosts: files mdns4 dns"), time.Hour) 443 order, _ = cnf.addrLookupOrder(nil, "192.0.2.1") 444 if order != hostLookupCgo { 445 t.Errorf("addrLookupOrder returned: %v, want cgo", order) 446 } 447 448} 449 450func setSystemNSS(nss *nssConf, addDur time.Duration) { 451 nssConfig.mu.Lock() 452 nssConfig.nssConf = nss 453 nssConfig.mu.Unlock() 454 nssConfig.acquireSema() 455 nssConfig.lastChecked = time.Now().Add(addDur) 456 nssConfig.releaseSema() 457} 458 459func TestSystemConf(t *testing.T) { 460 systemConf() 461} 462