github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/net/lookup_test.go (about) 1 // Copyright 2009 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 package net 6 7 import ( 8 "bytes" 9 "fmt" 10 "runtime" 11 "strings" 12 "testing" 13 "time" 14 ) 15 16 func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { 17 switch host { 18 case "localhost": 19 return []IPAddr{ 20 {IP: IPv4(127, 0, 0, 1)}, 21 {IP: IPv6loopback}, 22 }, nil 23 default: 24 return fn(host) 25 } 26 } 27 28 // The Lookup APIs use various sources such as local database, DNS or 29 // mDNS, and may use platform-dependent DNS stub resolver if possible. 30 // The APIs accept any of forms for a query; host name in various 31 // encodings, UTF-8 encoded net name, domain name, FQDN or absolute 32 // FQDN, but the result would be one of the forms and it depends on 33 // the circumstances. 34 35 var lookupGoogleSRVTests = []struct { 36 service, proto, name string 37 cname, target string 38 }{ 39 { 40 "xmpp-server", "tcp", "google.com", 41 "google.com.", "google.com.", 42 }, 43 { 44 "xmpp-server", "tcp", "google.com.", 45 "google.com.", "google.com.", 46 }, 47 48 // non-standard back door 49 { 50 "", "", "_xmpp-server._tcp.google.com", 51 "google.com.", "google.com.", 52 }, 53 { 54 "", "", "_xmpp-server._tcp.google.com.", 55 "google.com.", "google.com.", 56 }, 57 } 58 59 func TestLookupGoogleSRV(t *testing.T) { 60 if testing.Short() || !*testExternal { 61 t.Skip("avoid external network") 62 } 63 if !supportsIPv4 || !*testIPv4 { 64 t.Skip("IPv4 is required") 65 } 66 67 for _, tt := range lookupGoogleSRVTests { 68 cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name) 69 if err != nil { 70 t.Fatal(err) 71 } 72 if len(srvs) == 0 { 73 t.Error("got no record") 74 } 75 if !strings.HasSuffix(cname, tt.cname) { 76 t.Errorf("got %s; want %s", cname, tt.cname) 77 } 78 for _, srv := range srvs { 79 if !strings.HasSuffix(srv.Target, tt.target) { 80 t.Errorf("got %v; want a record containing %s", srv, tt.target) 81 } 82 } 83 } 84 } 85 86 var lookupGmailMXTests = []struct { 87 name, host string 88 }{ 89 {"gmail.com", "google.com."}, 90 {"gmail.com.", "google.com."}, 91 } 92 93 func TestLookupGmailMX(t *testing.T) { 94 if testing.Short() || !*testExternal { 95 t.Skip("avoid external network") 96 } 97 if !supportsIPv4 || !*testIPv4 { 98 t.Skip("IPv4 is required") 99 } 100 101 for _, tt := range lookupGmailMXTests { 102 mxs, err := LookupMX(tt.name) 103 if err != nil { 104 t.Fatal(err) 105 } 106 if len(mxs) == 0 { 107 t.Error("got no record") 108 } 109 for _, mx := range mxs { 110 if !strings.HasSuffix(mx.Host, tt.host) { 111 t.Errorf("got %v; want a record containing %s", mx, tt.host) 112 } 113 } 114 } 115 } 116 117 var lookupGmailNSTests = []struct { 118 name, host string 119 }{ 120 {"gmail.com", "google.com."}, 121 {"gmail.com.", "google.com."}, 122 } 123 124 func TestLookupGmailNS(t *testing.T) { 125 if testing.Short() || !*testExternal { 126 t.Skip("avoid external network") 127 } 128 if !supportsIPv4 || !*testIPv4 { 129 t.Skip("IPv4 is required") 130 } 131 132 for _, tt := range lookupGmailNSTests { 133 nss, err := LookupNS(tt.name) 134 if err != nil { 135 t.Fatal(err) 136 } 137 if len(nss) == 0 { 138 t.Error("got no record") 139 } 140 for _, ns := range nss { 141 if !strings.HasSuffix(ns.Host, tt.host) { 142 t.Errorf("got %v; want a record containing %s", ns, tt.host) 143 } 144 } 145 } 146 } 147 148 var lookupGmailTXTTests = []struct { 149 name, txt, host string 150 }{ 151 {"gmail.com", "spf", "google.com"}, 152 {"gmail.com.", "spf", "google.com"}, 153 } 154 155 func TestLookupGmailTXT(t *testing.T) { 156 if testing.Short() || !*testExternal { 157 t.Skip("avoid external network") 158 } 159 if !supportsIPv4 || !*testIPv4 { 160 t.Skip("IPv4 is required") 161 } 162 163 for _, tt := range lookupGmailTXTTests { 164 txts, err := LookupTXT(tt.name) 165 if err != nil { 166 t.Fatal(err) 167 } 168 if len(txts) == 0 { 169 t.Error("got no record") 170 } 171 for _, txt := range txts { 172 if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) { 173 t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host) 174 } 175 } 176 } 177 } 178 179 var lookupGooglePublicDNSAddrTests = []struct { 180 addr, name string 181 }{ 182 {"8.8.8.8", ".google.com."}, 183 {"8.8.4.4", ".google.com."}, 184 185 {"2001:4860:4860::8888", ".google.com."}, 186 {"2001:4860:4860::8844", ".google.com."}, 187 } 188 189 func TestLookupGooglePublicDNSAddr(t *testing.T) { 190 if testing.Short() || !*testExternal { 191 t.Skip("avoid external network") 192 } 193 if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { 194 t.Skip("both IPv4 and IPv6 are required") 195 } 196 197 for _, tt := range lookupGooglePublicDNSAddrTests { 198 names, err := LookupAddr(tt.addr) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if len(names) == 0 { 203 t.Error("got no record") 204 } 205 for _, name := range names { 206 if !strings.HasSuffix(name, tt.name) { 207 t.Errorf("got %s; want a record containing %s", name, tt.name) 208 } 209 } 210 } 211 } 212 213 func TestLookupIPv6LinkLocalAddr(t *testing.T) { 214 if !supportsIPv6 { 215 t.Skip("IPv6 is required") 216 } 217 218 addrs, err := LookupHost("localhost") 219 if err != nil { 220 t.Fatal(err) 221 } 222 found := false 223 for _, addr := range addrs { 224 if addr == "fe80::1%lo0" { 225 found = true 226 break 227 } 228 } 229 if !found { 230 t.Skipf("not supported on %s", runtime.GOOS) 231 } 232 if _, err := LookupAddr("fe80::1%lo0"); err != nil { 233 t.Error(err) 234 } 235 } 236 237 var lookupIANACNAMETests = []struct { 238 name, cname string 239 }{ 240 {"www.iana.org", "icann.org."}, 241 {"www.iana.org.", "icann.org."}, 242 } 243 244 func TestLookupIANACNAME(t *testing.T) { 245 if testing.Short() || !*testExternal { 246 t.Skip("avoid external network") 247 } 248 if !supportsIPv4 || !*testIPv4 { 249 t.Skip("IPv4 is required") 250 } 251 252 for _, tt := range lookupIANACNAMETests { 253 cname, err := LookupCNAME(tt.name) 254 if err != nil { 255 t.Fatal(err) 256 } 257 if !strings.HasSuffix(cname, tt.cname) { 258 t.Errorf("got %s; want a record containing %s", cname, tt.cname) 259 } 260 } 261 } 262 263 var lookupGoogleHostTests = []struct { 264 name string 265 }{ 266 {"google.com"}, 267 {"google.com."}, 268 } 269 270 func TestLookupGoogleHost(t *testing.T) { 271 if testing.Short() || !*testExternal { 272 t.Skip("avoid external network") 273 } 274 if !supportsIPv4 || !*testIPv4 { 275 t.Skip("IPv4 is required") 276 } 277 278 for _, tt := range lookupGoogleHostTests { 279 addrs, err := LookupHost(tt.name) 280 if err != nil { 281 t.Fatal(err) 282 } 283 if len(addrs) == 0 { 284 t.Error("got no record") 285 } 286 for _, addr := range addrs { 287 if ParseIP(addr) == nil { 288 t.Errorf("got %q; want a literal IP address", addr) 289 } 290 } 291 } 292 } 293 294 var lookupGoogleIPTests = []struct { 295 name string 296 }{ 297 {"google.com"}, 298 {"google.com."}, 299 } 300 301 func TestLookupGoogleIP(t *testing.T) { 302 if testing.Short() || !*testExternal { 303 t.Skip("avoid external network") 304 } 305 if !supportsIPv4 || !*testIPv4 { 306 t.Skip("IPv4 is required") 307 } 308 309 for _, tt := range lookupGoogleIPTests { 310 ips, err := LookupIP(tt.name) 311 if err != nil { 312 t.Fatal(err) 313 } 314 if len(ips) == 0 { 315 t.Error("got no record") 316 } 317 for _, ip := range ips { 318 if ip.To4() == nil && ip.To16() == nil { 319 t.Errorf("got %v; want an IP address", ip) 320 } 321 } 322 } 323 } 324 325 var revAddrTests = []struct { 326 Addr string 327 Reverse string 328 ErrPrefix string 329 }{ 330 {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, 331 {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, 332 {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, 333 {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""}, 334 {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""}, 335 {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, 336 {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, 337 {"1.2.3", "", "unrecognized address"}, 338 {"1.2.3.4.5", "", "unrecognized address"}, 339 {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, 340 {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, 341 } 342 343 func TestReverseAddress(t *testing.T) { 344 for i, tt := range revAddrTests { 345 a, err := reverseaddr(tt.Addr) 346 if len(tt.ErrPrefix) > 0 && err == nil { 347 t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix) 348 continue 349 } 350 if len(tt.ErrPrefix) == 0 && err != nil { 351 t.Errorf("#%d: expected <nil>, got %q (error)", i, err) 352 } 353 if err != nil && err.(*DNSError).Err != tt.ErrPrefix { 354 t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err) 355 } 356 if a != tt.Reverse { 357 t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) 358 } 359 } 360 } 361 362 func TestLookupIPDeadline(t *testing.T) { 363 if !*testDNSFlood { 364 t.Skip("test disabled; use -dnsflood to enable") 365 } 366 367 const N = 5000 368 const timeout = 3 * time.Second 369 c := make(chan error, 2*N) 370 for i := 0; i < N; i++ { 371 name := fmt.Sprintf("%d.net-test.golang.org", i) 372 go func() { 373 _, err := lookupIPDeadline(name, time.Now().Add(timeout/2)) 374 c <- err 375 }() 376 go func() { 377 _, err := lookupIPDeadline(name, time.Now().Add(timeout)) 378 c <- err 379 }() 380 } 381 qstats := struct { 382 succeeded, failed int 383 timeout, temporary, other int 384 unknown int 385 }{} 386 deadline := time.After(timeout + time.Second) 387 for i := 0; i < 2*N; i++ { 388 select { 389 case <-deadline: 390 t.Fatal("deadline exceeded") 391 case err := <-c: 392 switch err := err.(type) { 393 case nil: 394 qstats.succeeded++ 395 case Error: 396 qstats.failed++ 397 if err.Timeout() { 398 qstats.timeout++ 399 } 400 if err.Temporary() { 401 qstats.temporary++ 402 } 403 if !err.Timeout() && !err.Temporary() { 404 qstats.other++ 405 } 406 default: 407 qstats.failed++ 408 qstats.unknown++ 409 } 410 } 411 } 412 413 // A high volume of DNS queries for sub-domain of golang.org 414 // would be coordinated by authoritative or recursive server, 415 // or stub resolver which implements query-response rate 416 // limitation, so we can expect some query successes and more 417 // failures including timeout, temporary and other here. 418 // As a rule, unknown must not be shown but it might possibly 419 // happen due to issue 4856 for now. 420 t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown) 421 } 422 423 func TestLookupDotsWithLocalSource(t *testing.T) { 424 if !supportsIPv4 { 425 t.Skip("IPv4 is required") 426 } 427 428 for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} { 429 fixup := fn() 430 if fixup == nil { 431 continue 432 } 433 names, err := LookupAddr("127.0.0.1") 434 fixup() 435 if err != nil { 436 t.Errorf("#%d: %v", i, err) 437 continue 438 } 439 for _, name := range names { 440 if !strings.HasSuffix(name, ".") { 441 t.Errorf("#%d: got %s; want name ending with trailing dot", i, name) 442 } 443 } 444 } 445 } 446 447 func TestLookupDotsWithRemoteSource(t *testing.T) { 448 if testing.Short() || !*testExternal { 449 t.Skipf("skipping external network test") 450 } 451 452 if fixup := forceGoDNS(); fixup != nil { 453 testDots(t, "go") 454 fixup() 455 } 456 if fixup := forceCgoDNS(); fixup != nil { 457 testDots(t, "cgo") 458 fixup() 459 } 460 } 461 462 func testDots(t *testing.T, mode string) { 463 names, err := LookupAddr("8.8.8.8") // Google dns server 464 if err != nil { 465 t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode) 466 } else { 467 for _, name := range names { 468 if !strings.HasSuffix(name, ".google.com.") { 469 t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode) 470 break 471 } 472 } 473 } 474 475 cname, err := LookupCNAME("www.mit.edu") 476 if err != nil || !strings.HasSuffix(cname, ".") { 477 t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode) 478 } 479 480 mxs, err := LookupMX("google.com") 481 if err != nil { 482 t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode) 483 } else { 484 for _, mx := range mxs { 485 if !strings.HasSuffix(mx.Host, ".google.com.") { 486 t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode) 487 break 488 } 489 } 490 } 491 492 nss, err := LookupNS("google.com") 493 if err != nil { 494 t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode) 495 } else { 496 for _, ns := range nss { 497 if !strings.HasSuffix(ns.Host, ".google.com.") { 498 t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode) 499 break 500 } 501 } 502 } 503 504 cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com") 505 if err != nil { 506 t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode) 507 } else { 508 if !strings.HasSuffix(cname, ".google.com.") { 509 t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode) 510 } 511 for _, srv := range srvs { 512 if !strings.HasSuffix(srv.Target, ".google.com.") { 513 t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned addrs=%v, want names ending in .google.com. with trailing dot (mode=%v)", srvString(srvs), mode) 514 break 515 } 516 } 517 } 518 } 519 520 func mxString(mxs []*MX) string { 521 var buf bytes.Buffer 522 sep := "" 523 fmt.Fprintf(&buf, "[") 524 for _, mx := range mxs { 525 fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref) 526 sep = " " 527 } 528 fmt.Fprintf(&buf, "]") 529 return buf.String() 530 } 531 532 func nsString(nss []*NS) string { 533 var buf bytes.Buffer 534 sep := "" 535 fmt.Fprintf(&buf, "[") 536 for _, ns := range nss { 537 fmt.Fprintf(&buf, "%s%s", sep, ns.Host) 538 sep = " " 539 } 540 fmt.Fprintf(&buf, "]") 541 return buf.String() 542 } 543 544 func srvString(srvs []*SRV) string { 545 var buf bytes.Buffer 546 sep := "" 547 fmt.Fprintf(&buf, "[") 548 for _, srv := range srvs { 549 fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight) 550 sep = " " 551 } 552 fmt.Fprintf(&buf, "]") 553 return buf.String() 554 } 555 556 var lookupPortTests = []struct { 557 network string 558 name string 559 port int 560 ok bool 561 }{ 562 {"tcp", "0", 0, true}, 563 {"tcp", "echo", 7, true}, 564 {"tcp", "discard", 9, true}, 565 {"tcp", "systat", 11, true}, 566 {"tcp", "daytime", 13, true}, 567 {"tcp", "chargen", 19, true}, 568 {"tcp", "ftp-data", 20, true}, 569 {"tcp", "ftp", 21, true}, 570 {"tcp", "telnet", 23, true}, 571 {"tcp", "smtp", 25, true}, 572 {"tcp", "time", 37, true}, 573 {"tcp", "domain", 53, true}, 574 {"tcp", "finger", 79, true}, 575 {"tcp", "42", 42, true}, 576 577 {"udp", "0", 0, true}, 578 {"udp", "echo", 7, true}, 579 {"udp", "tftp", 69, true}, 580 {"udp", "bootpc", 68, true}, 581 {"udp", "bootps", 67, true}, 582 {"udp", "domain", 53, true}, 583 {"udp", "ntp", 123, true}, 584 {"udp", "snmp", 161, true}, 585 {"udp", "syslog", 514, true}, 586 {"udp", "42", 42, true}, 587 588 {"--badnet--", "zzz", 0, false}, 589 {"tcp", "--badport--", 0, false}, 590 {"tcp", "-1", 0, false}, 591 {"tcp", "65536", 0, false}, 592 {"udp", "-1", 0, false}, 593 {"udp", "65536", 0, false}, 594 } 595 596 func TestLookupPort(t *testing.T) { 597 switch runtime.GOOS { 598 case "nacl": 599 t.Skipf("not supported on %s", runtime.GOOS) 600 } 601 602 for _, tt := range lookupPortTests { 603 if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok { 604 t.Errorf("LookupPort(%q, %q) = %d, %v; want %d", tt.network, tt.name, port, err, tt.port) 605 } 606 } 607 }