Home | History | Annotate | Download | only in net
      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 	"context"
     10 	"fmt"
     11 	"internal/testenv"
     12 	"runtime"
     13 	"strings"
     14 	"testing"
     15 	"time"
     16 )
     17 
     18 func lookupLocalhost(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
     19 	switch host {
     20 	case "localhost":
     21 		return []IPAddr{
     22 			{IP: IPv4(127, 0, 0, 1)},
     23 			{IP: IPv6loopback},
     24 		}, nil
     25 	default:
     26 		return fn(ctx, host)
     27 	}
     28 }
     29 
     30 // The Lookup APIs use various sources such as local database, DNS or
     31 // mDNS, and may use platform-dependent DNS stub resolver if possible.
     32 // The APIs accept any of forms for a query; host name in various
     33 // encodings, UTF-8 encoded net name, domain name, FQDN or absolute
     34 // FQDN, but the result would be one of the forms and it depends on
     35 // the circumstances.
     36 
     37 var lookupGoogleSRVTests = []struct {
     38 	service, proto, name string
     39 	cname, target        string
     40 }{
     41 	{
     42 		"xmpp-server", "tcp", "google.com",
     43 		"google.com.", "google.com.",
     44 	},
     45 	{
     46 		"xmpp-server", "tcp", "google.com.",
     47 		"google.com.", "google.com.",
     48 	},
     49 
     50 	// non-standard back door
     51 	{
     52 		"", "", "_xmpp-server._tcp.google.com",
     53 		"google.com.", "google.com.",
     54 	},
     55 	{
     56 		"", "", "_xmpp-server._tcp.google.com.",
     57 		"google.com.", "google.com.",
     58 	},
     59 }
     60 
     61 func TestLookupGoogleSRV(t *testing.T) {
     62 	if testenv.Builder() == "" {
     63 		testenv.MustHaveExternalNetwork(t)
     64 	}
     65 
     66 	if !supportsIPv4 || !*testIPv4 {
     67 		t.Skip("IPv4 is required")
     68 	}
     69 
     70 	for _, tt := range lookupGoogleSRVTests {
     71 		cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
     72 		if err != nil {
     73 			testenv.SkipFlakyNet(t)
     74 			t.Fatal(err)
     75 		}
     76 		if len(srvs) == 0 {
     77 			t.Error("got no record")
     78 		}
     79 		if !strings.HasSuffix(cname, tt.cname) {
     80 			t.Errorf("got %s; want %s", cname, tt.cname)
     81 		}
     82 		for _, srv := range srvs {
     83 			if !strings.HasSuffix(srv.Target, tt.target) {
     84 				t.Errorf("got %v; want a record containing %s", srv, tt.target)
     85 			}
     86 		}
     87 	}
     88 }
     89 
     90 var lookupGmailMXTests = []struct {
     91 	name, host string
     92 }{
     93 	{"gmail.com", "google.com."},
     94 	{"gmail.com.", "google.com."},
     95 }
     96 
     97 func TestLookupGmailMX(t *testing.T) {
     98 	if testenv.Builder() == "" {
     99 		testenv.MustHaveExternalNetwork(t)
    100 	}
    101 
    102 	if !supportsIPv4 || !*testIPv4 {
    103 		t.Skip("IPv4 is required")
    104 	}
    105 
    106 	for _, tt := range lookupGmailMXTests {
    107 		mxs, err := LookupMX(tt.name)
    108 		if err != nil {
    109 			t.Fatal(err)
    110 		}
    111 		if len(mxs) == 0 {
    112 			t.Error("got no record")
    113 		}
    114 		for _, mx := range mxs {
    115 			if !strings.HasSuffix(mx.Host, tt.host) {
    116 				t.Errorf("got %v; want a record containing %s", mx, tt.host)
    117 			}
    118 		}
    119 	}
    120 }
    121 
    122 var lookupGmailNSTests = []struct {
    123 	name, host string
    124 }{
    125 	{"gmail.com", "google.com."},
    126 	{"gmail.com.", "google.com."},
    127 }
    128 
    129 func TestLookupGmailNS(t *testing.T) {
    130 	if testenv.Builder() == "" {
    131 		testenv.MustHaveExternalNetwork(t)
    132 	}
    133 
    134 	if !supportsIPv4 || !*testIPv4 {
    135 		t.Skip("IPv4 is required")
    136 	}
    137 
    138 	for _, tt := range lookupGmailNSTests {
    139 		nss, err := LookupNS(tt.name)
    140 		if err != nil {
    141 			testenv.SkipFlakyNet(t)
    142 			t.Fatal(err)
    143 		}
    144 		if len(nss) == 0 {
    145 			t.Error("got no record")
    146 		}
    147 		for _, ns := range nss {
    148 			if !strings.HasSuffix(ns.Host, tt.host) {
    149 				t.Errorf("got %v; want a record containing %s", ns, tt.host)
    150 			}
    151 		}
    152 	}
    153 }
    154 
    155 var lookupGmailTXTTests = []struct {
    156 	name, txt, host string
    157 }{
    158 	{"gmail.com", "spf", "google.com"},
    159 	{"gmail.com.", "spf", "google.com"},
    160 }
    161 
    162 func TestLookupGmailTXT(t *testing.T) {
    163 	if testenv.Builder() == "" {
    164 		testenv.MustHaveExternalNetwork(t)
    165 	}
    166 
    167 	if !supportsIPv4 || !*testIPv4 {
    168 		t.Skip("IPv4 is required")
    169 	}
    170 
    171 	for _, tt := range lookupGmailTXTTests {
    172 		txts, err := LookupTXT(tt.name)
    173 		if err != nil {
    174 			t.Fatal(err)
    175 		}
    176 		if len(txts) == 0 {
    177 			t.Error("got no record")
    178 		}
    179 		for _, txt := range txts {
    180 			if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) {
    181 				t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host)
    182 			}
    183 		}
    184 	}
    185 }
    186 
    187 var lookupGooglePublicDNSAddrTests = []struct {
    188 	addr, name string
    189 }{
    190 	{"8.8.8.8", ".google.com."},
    191 	{"8.8.4.4", ".google.com."},
    192 
    193 	{"2001:4860:4860::8888", ".google.com."},
    194 	{"2001:4860:4860::8844", ".google.com."},
    195 }
    196 
    197 func TestLookupGooglePublicDNSAddr(t *testing.T) {
    198 	if testenv.Builder() == "" {
    199 		testenv.MustHaveExternalNetwork(t)
    200 	}
    201 
    202 	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
    203 		t.Skip("both IPv4 and IPv6 are required")
    204 	}
    205 
    206 	for _, tt := range lookupGooglePublicDNSAddrTests {
    207 		names, err := LookupAddr(tt.addr)
    208 		if err != nil {
    209 			t.Fatal(err)
    210 		}
    211 		if len(names) == 0 {
    212 			t.Error("got no record")
    213 		}
    214 		for _, name := range names {
    215 			if !strings.HasSuffix(name, tt.name) {
    216 				t.Errorf("got %s; want a record containing %s", name, tt.name)
    217 			}
    218 		}
    219 	}
    220 }
    221 
    222 func TestLookupIPv6LinkLocalAddr(t *testing.T) {
    223 	if !supportsIPv6 || !*testIPv6 {
    224 		t.Skip("IPv6 is required")
    225 	}
    226 
    227 	addrs, err := LookupHost("localhost")
    228 	if err != nil {
    229 		t.Fatal(err)
    230 	}
    231 	found := false
    232 	for _, addr := range addrs {
    233 		if addr == "fe80::1%lo0" {
    234 			found = true
    235 			break
    236 		}
    237 	}
    238 	if !found {
    239 		t.Skipf("not supported on %s", runtime.GOOS)
    240 	}
    241 	if _, err := LookupAddr("fe80::1%lo0"); err != nil {
    242 		t.Error(err)
    243 	}
    244 }
    245 
    246 var lookupCNAMETests = []struct {
    247 	name, cname string
    248 }{
    249 	{"www.iana.org", "icann.org."},
    250 	{"www.iana.org.", "icann.org."},
    251 	{"www.google.com", "google.com."},
    252 }
    253 
    254 func TestLookupCNAME(t *testing.T) {
    255 	if testenv.Builder() == "" {
    256 		testenv.MustHaveExternalNetwork(t)
    257 	}
    258 
    259 	if !supportsIPv4 || !*testIPv4 {
    260 		t.Skip("IPv4 is required")
    261 	}
    262 
    263 	for _, tt := range lookupCNAMETests {
    264 		cname, err := LookupCNAME(tt.name)
    265 		if err != nil {
    266 			t.Fatal(err)
    267 		}
    268 		if !strings.HasSuffix(cname, tt.cname) {
    269 			t.Errorf("got %s; want a record containing %s", cname, tt.cname)
    270 		}
    271 	}
    272 }
    273 
    274 var lookupGoogleHostTests = []struct {
    275 	name string
    276 }{
    277 	{"google.com"},
    278 	{"google.com."},
    279 }
    280 
    281 func TestLookupGoogleHost(t *testing.T) {
    282 	if testenv.Builder() == "" {
    283 		testenv.MustHaveExternalNetwork(t)
    284 	}
    285 
    286 	if !supportsIPv4 || !*testIPv4 {
    287 		t.Skip("IPv4 is required")
    288 	}
    289 
    290 	for _, tt := range lookupGoogleHostTests {
    291 		addrs, err := LookupHost(tt.name)
    292 		if err != nil {
    293 			t.Fatal(err)
    294 		}
    295 		if len(addrs) == 0 {
    296 			t.Error("got no record")
    297 		}
    298 		for _, addr := range addrs {
    299 			if ParseIP(addr) == nil {
    300 				t.Errorf("got %q; want a literal IP address", addr)
    301 			}
    302 		}
    303 	}
    304 }
    305 
    306 var lookupGoogleIPTests = []struct {
    307 	name string
    308 }{
    309 	{"google.com"},
    310 	{"google.com."},
    311 }
    312 
    313 func TestLookupGoogleIP(t *testing.T) {
    314 	if testenv.Builder() == "" {
    315 		testenv.MustHaveExternalNetwork(t)
    316 	}
    317 
    318 	if !supportsIPv4 || !*testIPv4 {
    319 		t.Skip("IPv4 is required")
    320 	}
    321 
    322 	for _, tt := range lookupGoogleIPTests {
    323 		ips, err := LookupIP(tt.name)
    324 		if err != nil {
    325 			t.Fatal(err)
    326 		}
    327 		if len(ips) == 0 {
    328 			t.Error("got no record")
    329 		}
    330 		for _, ip := range ips {
    331 			if ip.To4() == nil && ip.To16() == nil {
    332 				t.Errorf("got %v; want an IP address", ip)
    333 			}
    334 		}
    335 	}
    336 }
    337 
    338 var revAddrTests = []struct {
    339 	Addr      string
    340 	Reverse   string
    341 	ErrPrefix string
    342 }{
    343 	{"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""},
    344 	{"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""},
    345 	{"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""},
    346 	{"::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.", ""},
    347 	{"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.", ""},
    348 	{"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.", ""},
    349 	{"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.", ""},
    350 	{"1.2.3", "", "unrecognized address"},
    351 	{"1.2.3.4.5", "", "unrecognized address"},
    352 	{"1234:567:bcbca::89a:bcde", "", "unrecognized address"},
    353 	{"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"},
    354 }
    355 
    356 func TestReverseAddress(t *testing.T) {
    357 	for i, tt := range revAddrTests {
    358 		a, err := reverseaddr(tt.Addr)
    359 		if len(tt.ErrPrefix) > 0 && err == nil {
    360 			t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix)
    361 			continue
    362 		}
    363 		if len(tt.ErrPrefix) == 0 && err != nil {
    364 			t.Errorf("#%d: expected <nil>, got %q (error)", i, err)
    365 		}
    366 		if err != nil && err.(*DNSError).Err != tt.ErrPrefix {
    367 			t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err)
    368 		}
    369 		if a != tt.Reverse {
    370 			t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a)
    371 		}
    372 	}
    373 }
    374 
    375 func TestDNSFlood(t *testing.T) {
    376 	if !*testDNSFlood {
    377 		t.Skip("test disabled; use -dnsflood to enable")
    378 	}
    379 
    380 	var N = 5000
    381 	if runtime.GOOS == "darwin" {
    382 		// On Darwin this test consumes kernel threads much
    383 		// than other platforms for some reason.
    384 		// When we monitor the number of allocated Ms by
    385 		// observing on runtime.newm calls, we can see that it
    386 		// easily reaches the per process ceiling
    387 		// kern.num_threads when CGO_ENABLED=1 and
    388 		// GODEBUG=netdns=go.
    389 		N = 500
    390 	}
    391 
    392 	const timeout = 3 * time.Second
    393 	ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2)
    394 	defer cancel()
    395 	ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
    396 	defer cancel()
    397 
    398 	c := make(chan error, 2*N)
    399 	for i := 0; i < N; i++ {
    400 		name := fmt.Sprintf("%d.net-test.golang.org", i)
    401 		go func() {
    402 			_, err := DefaultResolver.LookupIPAddr(ctxHalfTimeout, name)
    403 			c <- err
    404 		}()
    405 		go func() {
    406 			_, err := DefaultResolver.LookupIPAddr(ctxTimeout, name)
    407 			c <- err
    408 		}()
    409 	}
    410 	qstats := struct {
    411 		succeeded, failed         int
    412 		timeout, temporary, other int
    413 		unknown                   int
    414 	}{}
    415 	deadline := time.After(timeout + time.Second)
    416 	for i := 0; i < 2*N; i++ {
    417 		select {
    418 		case <-deadline:
    419 			t.Fatal("deadline exceeded")
    420 		case err := <-c:
    421 			switch err := err.(type) {
    422 			case nil:
    423 				qstats.succeeded++
    424 			case Error:
    425 				qstats.failed++
    426 				if err.Timeout() {
    427 					qstats.timeout++
    428 				}
    429 				if err.Temporary() {
    430 					qstats.temporary++
    431 				}
    432 				if !err.Timeout() && !err.Temporary() {
    433 					qstats.other++
    434 				}
    435 			default:
    436 				qstats.failed++
    437 				qstats.unknown++
    438 			}
    439 		}
    440 	}
    441 
    442 	// A high volume of DNS queries for sub-domain of golang.org
    443 	// would be coordinated by authoritative or recursive server,
    444 	// or stub resolver which implements query-response rate
    445 	// limitation, so we can expect some query successes and more
    446 	// failures including timeout, temporary and other here.
    447 	// As a rule, unknown must not be shown but it might possibly
    448 	// happen due to issue 4856 for now.
    449 	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)
    450 }
    451 
    452 func TestLookupDotsWithLocalSource(t *testing.T) {
    453 	if !supportsIPv4 || !*testIPv4 {
    454 		t.Skip("IPv4 is required")
    455 	}
    456 
    457 	if testenv.Builder() == "" {
    458 		testenv.MustHaveExternalNetwork(t)
    459 	}
    460 
    461 	for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
    462 		fixup := fn()
    463 		if fixup == nil {
    464 			continue
    465 		}
    466 		names, err := LookupAddr("127.0.0.1")
    467 		fixup()
    468 		if err != nil {
    469 			t.Logf("#%d: %v", i, err)
    470 			continue
    471 		}
    472 		mode := "netgo"
    473 		if i == 1 {
    474 			mode = "netcgo"
    475 		}
    476 	loop:
    477 		for i, name := range names {
    478 			if strings.Index(name, ".") == len(name)-1 { // "localhost" not "localhost."
    479 				for j := range names {
    480 					if j == i {
    481 						continue
    482 					}
    483 					if names[j] == name[:len(name)-1] {
    484 						// It's OK if we find the name without the dot,
    485 						// as some systems say 127.0.0.1 localhost localhost.
    486 						continue loop
    487 					}
    488 				}
    489 				t.Errorf("%s: got %s; want %s", mode, name, name[:len(name)-1])
    490 			} else if strings.Contains(name, ".") && !strings.HasSuffix(name, ".") { // "localhost.localdomain." not "localhost.localdomain"
    491 				t.Errorf("%s: got %s; want name ending with trailing dot", mode, name)
    492 			}
    493 		}
    494 	}
    495 }
    496 
    497 func TestLookupDotsWithRemoteSource(t *testing.T) {
    498 	if testenv.Builder() == "" {
    499 		testenv.MustHaveExternalNetwork(t)
    500 	}
    501 
    502 	if !supportsIPv4 || !*testIPv4 {
    503 		t.Skip("IPv4 is required")
    504 	}
    505 
    506 	if fixup := forceGoDNS(); fixup != nil {
    507 		testDots(t, "go")
    508 		fixup()
    509 	}
    510 	if fixup := forceCgoDNS(); fixup != nil {
    511 		testDots(t, "cgo")
    512 		fixup()
    513 	}
    514 }
    515 
    516 func testDots(t *testing.T, mode string) {
    517 	names, err := LookupAddr("8.8.8.8") // Google dns server
    518 	if err != nil {
    519 		testenv.SkipFlakyNet(t)
    520 		t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
    521 	} else {
    522 		for _, name := range names {
    523 			if !strings.HasSuffix(name, ".google.com.") {
    524 				t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
    525 				break
    526 			}
    527 		}
    528 	}
    529 
    530 	cname, err := LookupCNAME("www.mit.edu")
    531 	if err != nil {
    532 		testenv.SkipFlakyNet(t)
    533 		t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err)
    534 	} else if !strings.HasSuffix(cname, ".") {
    535 		t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode)
    536 	}
    537 
    538 	mxs, err := LookupMX("google.com")
    539 	if err != nil {
    540 		testenv.SkipFlakyNet(t)
    541 		t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
    542 	} else {
    543 		for _, mx := range mxs {
    544 			if !strings.HasSuffix(mx.Host, ".google.com.") {
    545 				t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
    546 				break
    547 			}
    548 		}
    549 	}
    550 
    551 	nss, err := LookupNS("google.com")
    552 	if err != nil {
    553 		testenv.SkipFlakyNet(t)
    554 		t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
    555 	} else {
    556 		for _, ns := range nss {
    557 			if !strings.HasSuffix(ns.Host, ".google.com.") {
    558 				t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
    559 				break
    560 			}
    561 		}
    562 	}
    563 
    564 	cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
    565 	if err != nil {
    566 		testenv.SkipFlakyNet(t)
    567 		t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
    568 	} else {
    569 		if !strings.HasSuffix(cname, ".google.com.") {
    570 			t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode)
    571 		}
    572 		for _, srv := range srvs {
    573 			if !strings.HasSuffix(srv.Target, ".google.com.") {
    574 				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)
    575 				break
    576 			}
    577 		}
    578 	}
    579 }
    580 
    581 func mxString(mxs []*MX) string {
    582 	var buf bytes.Buffer
    583 	sep := ""
    584 	fmt.Fprintf(&buf, "[")
    585 	for _, mx := range mxs {
    586 		fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
    587 		sep = " "
    588 	}
    589 	fmt.Fprintf(&buf, "]")
    590 	return buf.String()
    591 }
    592 
    593 func nsString(nss []*NS) string {
    594 	var buf bytes.Buffer
    595 	sep := ""
    596 	fmt.Fprintf(&buf, "[")
    597 	for _, ns := range nss {
    598 		fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
    599 		sep = " "
    600 	}
    601 	fmt.Fprintf(&buf, "]")
    602 	return buf.String()
    603 }
    604 
    605 func srvString(srvs []*SRV) string {
    606 	var buf bytes.Buffer
    607 	sep := ""
    608 	fmt.Fprintf(&buf, "[")
    609 	for _, srv := range srvs {
    610 		fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
    611 		sep = " "
    612 	}
    613 	fmt.Fprintf(&buf, "]")
    614 	return buf.String()
    615 }
    616 
    617 func TestLookupPort(t *testing.T) {
    618 	// See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
    619 	//
    620 	// Please be careful about adding new test cases.
    621 	// There are platforms having incomplete mappings for
    622 	// restricted resource access and security reasons.
    623 	type test struct {
    624 		network string
    625 		name    string
    626 		port    int
    627 		ok      bool
    628 	}
    629 	var tests = []test{
    630 		{"tcp", "0", 0, true},
    631 		{"udp", "0", 0, true},
    632 		{"udp", "domain", 53, true},
    633 
    634 		{"--badnet--", "zzz", 0, false},
    635 		{"tcp", "--badport--", 0, false},
    636 		{"tcp", "-1", 0, false},
    637 		{"tcp", "65536", 0, false},
    638 		{"udp", "-1", 0, false},
    639 		{"udp", "65536", 0, false},
    640 		{"tcp", "123456789", 0, false},
    641 
    642 		// Issue 13610: LookupPort("tcp", "")
    643 		{"tcp", "", 0, true},
    644 		{"tcp4", "", 0, true},
    645 		{"tcp6", "", 0, true},
    646 		{"udp", "", 0, true},
    647 		{"udp4", "", 0, true},
    648 		{"udp6", "", 0, true},
    649 	}
    650 
    651 	switch runtime.GOOS {
    652 	case "android":
    653 		if netGo {
    654 			t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS)
    655 		}
    656 	default:
    657 		tests = append(tests, test{"tcp", "http", 80, true})
    658 	}
    659 
    660 	for _, tt := range tests {
    661 		port, err := LookupPort(tt.network, tt.name)
    662 		if port != tt.port || (err == nil) != tt.ok {
    663 			t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok)
    664 		}
    665 		if err != nil {
    666 			if perr := parseLookupPortError(err); perr != nil {
    667 				t.Error(perr)
    668 			}
    669 		}
    670 	}
    671 }
    672 
    673 // Like TestLookupPort but with minimal tests that should always pass
    674 // because the answers are baked-in to the net package.
    675 func TestLookupPort_Minimal(t *testing.T) {
    676 	type test struct {
    677 		network string
    678 		name    string
    679 		port    int
    680 	}
    681 	var tests = []test{
    682 		{"tcp", "http", 80},
    683 		{"tcp", "HTTP", 80}, // case shouldn't matter
    684 		{"tcp", "https", 443},
    685 		{"tcp", "ssh", 22},
    686 		{"tcp", "gopher", 70},
    687 		{"tcp4", "http", 80},
    688 		{"tcp6", "http", 80},
    689 	}
    690 
    691 	for _, tt := range tests {
    692 		port, err := LookupPort(tt.network, tt.name)
    693 		if port != tt.port || err != nil {
    694 			t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt.network, tt.name, port, err, tt.port)
    695 		}
    696 	}
    697 }
    698 
    699 func TestLookupProtocol_Minimal(t *testing.T) {
    700 	type test struct {
    701 		name string
    702 		want int
    703 	}
    704 	var tests = []test{
    705 		{"tcp", 6},
    706 		{"TcP", 6}, // case shouldn't matter
    707 		{"icmp", 1},
    708 		{"igmp", 2},
    709 		{"udp", 17},
    710 		{"ipv6-icmp", 58},
    711 	}
    712 
    713 	for _, tt := range tests {
    714 		got, err := lookupProtocol(context.Background(), tt.name)
    715 		if got != tt.want || err != nil {
    716 			t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want)
    717 		}
    718 	}
    719 
    720 }
    721 
    722 func TestLookupNonLDH(t *testing.T) {
    723 	if runtime.GOOS == "nacl" {
    724 		t.Skip("skip on nacl")
    725 	}
    726 	if fixup := forceGoDNS(); fixup != nil {
    727 		defer fixup()
    728 	}
    729 
    730 	// "LDH" stands for letters, digits, and hyphens and is the usual
    731 	// description of standard DNS names.
    732 	// This test is checking that other kinds of names are reported
    733 	// as not found, not reported as invalid names.
    734 	addrs, err := LookupHost("!!!.###.bogus..domain.")
    735 	if err == nil {
    736 		t.Fatalf("lookup succeeded: %v", addrs)
    737 	}
    738 	if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) {
    739 		t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
    740 	}
    741 }
    742