1// Copyright 2011 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 5package net 6 7import ( 8 "bufio" 9 "context" 10 "errors" 11 "fmt" 12 "internal/testenv" 13 "io" 14 "os" 15 "runtime" 16 "strings" 17 "sync" 18 "syscall" 19 "testing" 20 "time" 21) 22 23var prohibitionaryDialArgTests = []struct { 24 network string 25 address string 26}{ 27 {"tcp6", "127.0.0.1"}, 28 {"tcp6", "::ffff:127.0.0.1"}, 29} 30 31func TestProhibitionaryDialArg(t *testing.T) { 32 testenv.MustHaveExternalNetwork(t) 33 34 switch runtime.GOOS { 35 case "plan9": 36 t.Skipf("not supported on %s", runtime.GOOS) 37 } 38 if !supportsIPv4map() { 39 t.Skip("mapping ipv4 address inside ipv6 address not supported") 40 } 41 42 ln, err := Listen("tcp", "[::]:0") 43 if err != nil { 44 t.Fatal(err) 45 } 46 defer ln.Close() 47 48 _, port, err := SplitHostPort(ln.Addr().String()) 49 if err != nil { 50 t.Fatal(err) 51 } 52 53 for i, tt := range prohibitionaryDialArgTests { 54 c, err := Dial(tt.network, JoinHostPort(tt.address, port)) 55 if err == nil { 56 c.Close() 57 t.Errorf("#%d: %v", i, err) 58 } 59 } 60} 61 62func TestDialLocal(t *testing.T) { 63 ln := newLocalListener(t, "tcp") 64 defer ln.Close() 65 _, port, err := SplitHostPort(ln.Addr().String()) 66 if err != nil { 67 t.Fatal(err) 68 } 69 c, err := Dial("tcp", JoinHostPort("", port)) 70 if err != nil { 71 t.Fatal(err) 72 } 73 c.Close() 74} 75 76func TestDialerDualStackFDLeak(t *testing.T) { 77 switch runtime.GOOS { 78 case "plan9": 79 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 80 case "windows": 81 t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) 82 case "openbsd": 83 testenv.SkipFlaky(t, 15157) 84 } 85 if !supportsIPv4() || !supportsIPv6() { 86 t.Skip("both IPv4 and IPv6 are required") 87 } 88 89 before := sw.Sockets() 90 origTestHookLookupIP := testHookLookupIP 91 defer func() { testHookLookupIP = origTestHookLookupIP }() 92 testHookLookupIP = lookupLocalhost 93 handler := func(dss *dualStackServer, ln Listener) { 94 for { 95 c, err := ln.Accept() 96 if err != nil { 97 return 98 } 99 c.Close() 100 } 101 } 102 dss, err := newDualStackServer() 103 if err != nil { 104 t.Fatal(err) 105 } 106 if err := dss.buildup(handler); err != nil { 107 dss.teardown() 108 t.Fatal(err) 109 } 110 111 const N = 10 112 var wg sync.WaitGroup 113 wg.Add(N) 114 d := &Dialer{DualStack: true, Timeout: 5 * time.Second} 115 for i := 0; i < N; i++ { 116 go func() { 117 defer wg.Done() 118 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 119 if err != nil { 120 t.Error(err) 121 return 122 } 123 c.Close() 124 }() 125 } 126 wg.Wait() 127 dss.teardown() 128 after := sw.Sockets() 129 if len(after) != len(before) { 130 t.Errorf("got %d; want %d", len(after), len(before)) 131 } 132} 133 134// Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is 135// expected to hang until the timeout elapses. These addresses are reserved 136// for benchmarking by RFC 6890. 137const ( 138 slowDst4 = "198.18.0.254" 139 slowDst6 = "2001:2::254" 140) 141 142// In some environments, the slow IPs may be explicitly unreachable, and fail 143// more quickly than expected. This test hook prevents dialTCP from returning 144// before the deadline. 145func slowDialTCP(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) { 146 sd := &sysDialer{network: network, address: raddr.String()} 147 c, err := sd.doDialTCP(ctx, laddr, raddr) 148 if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) { 149 // Wait for the deadline, or indefinitely if none exists. 150 <-ctx.Done() 151 } 152 return c, err 153} 154 155func dialClosedPort(t *testing.T) (dialLatency time.Duration) { 156 // On most platforms, dialing a closed port should be nearly instantaneous — 157 // less than a few hundred milliseconds. However, on some platforms it may be 158 // much slower: on Windows and OpenBSD, it has been observed to take up to a 159 // few seconds. 160 161 l, err := Listen("tcp", "127.0.0.1:0") 162 if err != nil { 163 t.Fatalf("dialClosedPort: Listen failed: %v", err) 164 } 165 addr := l.Addr().String() 166 l.Close() 167 168 startTime := time.Now() 169 c, err := Dial("tcp", addr) 170 if err == nil { 171 c.Close() 172 } 173 elapsed := time.Since(startTime) 174 t.Logf("dialClosedPort: measured delay %v", elapsed) 175 return elapsed 176} 177 178func TestDialParallel(t *testing.T) { 179 const instant time.Duration = 0 180 const fallbackDelay = 200 * time.Millisecond 181 182 nCopies := func(s string, n int) []string { 183 out := make([]string, n) 184 for i := 0; i < n; i++ { 185 out[i] = s 186 } 187 return out 188 } 189 190 var testCases = []struct { 191 primaries []string 192 fallbacks []string 193 teardownNetwork string 194 expectOk bool 195 expectElapsed time.Duration 196 }{ 197 // These should just work on the first try. 198 {[]string{"127.0.0.1"}, []string{}, "", true, instant}, 199 {[]string{"::1"}, []string{}, "", true, instant}, 200 {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant}, 201 {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant}, 202 // Primary is slow; fallback should kick in. 203 {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay}, 204 // Skip a "connection refused" in the primary thread. 205 {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, instant}, 206 {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, instant}, 207 // Skip a "connection refused" in the fallback thread. 208 {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay}, 209 // Primary refused, fallback without delay. 210 {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, instant}, 211 {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, instant}, 212 // Everything is refused. 213 {[]string{"127.0.0.1"}, []string{}, "tcp4", false, instant}, 214 // Nothing to do; fail instantly. 215 {[]string{}, []string{}, "", false, instant}, 216 // Connecting to tons of addresses should not trip the deadline. 217 {nCopies("::1", 1000), []string{}, "", true, instant}, 218 } 219 220 // Convert a list of IP strings into TCPAddrs. 221 makeAddrs := func(ips []string, port string) addrList { 222 var out addrList 223 for _, ip := range ips { 224 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port)) 225 if err != nil { 226 t.Fatal(err) 227 } 228 out = append(out, addr) 229 } 230 return out 231 } 232 233 for i, tt := range testCases { 234 i, tt := i, tt 235 t.Run(fmt.Sprint(i), func(t *testing.T) { 236 dialTCP := func(ctx context.Context, network string, laddr, raddr *TCPAddr) (*TCPConn, error) { 237 n := "tcp6" 238 if raddr.IP.To4() != nil { 239 n = "tcp4" 240 } 241 if n == tt.teardownNetwork { 242 return nil, errors.New("unreachable") 243 } 244 if r := raddr.IP.String(); r == slowDst4 || r == slowDst6 { 245 <-ctx.Done() 246 return nil, ctx.Err() 247 } 248 return &TCPConn{}, nil 249 } 250 251 primaries := makeAddrs(tt.primaries, "80") 252 fallbacks := makeAddrs(tt.fallbacks, "80") 253 d := Dialer{ 254 FallbackDelay: fallbackDelay, 255 } 256 const forever = 60 * time.Minute 257 if tt.expectElapsed == instant { 258 d.FallbackDelay = forever 259 } 260 startTime := time.Now() 261 sd := &sysDialer{ 262 Dialer: d, 263 network: "tcp", 264 address: "?", 265 testHookDialTCP: dialTCP, 266 } 267 c, err := sd.dialParallel(context.Background(), primaries, fallbacks) 268 elapsed := time.Since(startTime) 269 270 if c != nil { 271 c.Close() 272 } 273 274 if tt.expectOk && err != nil { 275 t.Errorf("#%d: got %v; want nil", i, err) 276 } else if !tt.expectOk && err == nil { 277 t.Errorf("#%d: got nil; want non-nil", i) 278 } 279 280 if elapsed < tt.expectElapsed || elapsed >= forever { 281 t.Errorf("#%d: got %v; want >= %v, < forever", i, elapsed, tt.expectElapsed) 282 } 283 284 // Repeat each case, ensuring that it can be canceled. 285 ctx, cancel := context.WithCancel(context.Background()) 286 var wg sync.WaitGroup 287 wg.Add(1) 288 go func() { 289 time.Sleep(5 * time.Millisecond) 290 cancel() 291 wg.Done() 292 }() 293 // Ignore errors, since all we care about is that the 294 // call can be canceled. 295 c, _ = sd.dialParallel(ctx, primaries, fallbacks) 296 if c != nil { 297 c.Close() 298 } 299 wg.Wait() 300 }) 301 } 302} 303 304func lookupSlowFast(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) { 305 switch host { 306 case "slow6loopback4": 307 // Returns a slow IPv6 address, and a local IPv4 address. 308 return []IPAddr{ 309 {IP: ParseIP(slowDst6)}, 310 {IP: ParseIP("127.0.0.1")}, 311 }, nil 312 default: 313 return fn(ctx, network, host) 314 } 315} 316 317func TestDialerFallbackDelay(t *testing.T) { 318 testenv.MustHaveExternalNetwork(t) 319 320 if !supportsIPv4() || !supportsIPv6() { 321 t.Skip("both IPv4 and IPv6 are required") 322 } 323 324 origTestHookLookupIP := testHookLookupIP 325 defer func() { testHookLookupIP = origTestHookLookupIP }() 326 testHookLookupIP = lookupSlowFast 327 328 origTestHookDialTCP := testHookDialTCP 329 defer func() { testHookDialTCP = origTestHookDialTCP }() 330 testHookDialTCP = slowDialTCP 331 332 var testCases = []struct { 333 dualstack bool 334 delay time.Duration 335 expectElapsed time.Duration 336 }{ 337 // Use a very brief delay, which should fallback immediately. 338 {true, 1 * time.Nanosecond, 0}, 339 // Use a 200ms explicit timeout. 340 {true, 200 * time.Millisecond, 200 * time.Millisecond}, 341 // The default is 300ms. 342 {true, 0, 300 * time.Millisecond}, 343 } 344 345 handler := func(dss *dualStackServer, ln Listener) { 346 for { 347 c, err := ln.Accept() 348 if err != nil { 349 return 350 } 351 c.Close() 352 } 353 } 354 dss, err := newDualStackServer() 355 if err != nil { 356 t.Fatal(err) 357 } 358 defer dss.teardown() 359 if err := dss.buildup(handler); err != nil { 360 t.Fatal(err) 361 } 362 363 for i, tt := range testCases { 364 d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay} 365 366 startTime := time.Now() 367 c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port)) 368 elapsed := time.Since(startTime) 369 if err == nil { 370 c.Close() 371 } else if tt.dualstack { 372 t.Error(err) 373 } 374 expectMin := tt.expectElapsed - 1*time.Millisecond 375 expectMax := tt.expectElapsed + 95*time.Millisecond 376 if elapsed < expectMin { 377 t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin) 378 } 379 if elapsed > expectMax { 380 t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax) 381 } 382 } 383} 384 385func TestDialParallelSpuriousConnection(t *testing.T) { 386 if !supportsIPv4() || !supportsIPv6() { 387 t.Skip("both IPv4 and IPv6 are required") 388 } 389 390 var readDeadline time.Time 391 if td, ok := t.Deadline(); ok { 392 const arbitraryCleanupMargin = 1 * time.Second 393 readDeadline = td.Add(-arbitraryCleanupMargin) 394 } else { 395 readDeadline = time.Now().Add(5 * time.Second) 396 } 397 398 var closed sync.WaitGroup 399 closed.Add(2) 400 handler := func(dss *dualStackServer, ln Listener) { 401 // Accept one connection per address. 402 c, err := ln.Accept() 403 if err != nil { 404 t.Fatal(err) 405 } 406 407 // Workaround for https://go.dev/issue/37795. 408 // On arm64 macOS (current as of macOS 12.4), 409 // reading from a socket at the same time as the client 410 // is closing it occasionally hangs for 60 seconds before 411 // returning ECONNRESET. Sleep for a bit to give the 412 // socket time to close before trying to read from it. 413 if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { 414 time.Sleep(10 * time.Millisecond) 415 } 416 417 // The client should close itself, without sending data. 418 c.SetReadDeadline(readDeadline) 419 var b [1]byte 420 if _, err := c.Read(b[:]); err != io.EOF { 421 t.Errorf("got %v; want %v", err, io.EOF) 422 } 423 c.Close() 424 closed.Done() 425 } 426 dss, err := newDualStackServer() 427 if err != nil { 428 t.Fatal(err) 429 } 430 defer dss.teardown() 431 if err := dss.buildup(handler); err != nil { 432 t.Fatal(err) 433 } 434 435 const fallbackDelay = 100 * time.Millisecond 436 437 var dialing sync.WaitGroup 438 dialing.Add(2) 439 origTestHookDialTCP := testHookDialTCP 440 defer func() { testHookDialTCP = origTestHookDialTCP }() 441 testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) { 442 // Wait until Happy Eyeballs kicks in and both connections are dialing, 443 // and inhibit cancellation. 444 // This forces dialParallel to juggle two successful connections. 445 dialing.Done() 446 dialing.Wait() 447 448 // Now ignore the provided context (which will be canceled) and use a 449 // different one to make sure this completes with a valid connection, 450 // which we hope to be closed below: 451 sd := &sysDialer{network: net, address: raddr.String()} 452 return sd.doDialTCP(context.Background(), laddr, raddr) 453 } 454 455 d := Dialer{ 456 FallbackDelay: fallbackDelay, 457 } 458 sd := &sysDialer{ 459 Dialer: d, 460 network: "tcp", 461 address: "?", 462 } 463 464 makeAddr := func(ip string) addrList { 465 addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port)) 466 if err != nil { 467 t.Fatal(err) 468 } 469 return addrList{addr} 470 } 471 472 // dialParallel returns one connection (and closes the other.) 473 c, err := sd.dialParallel(context.Background(), makeAddr("127.0.0.1"), makeAddr("::1")) 474 if err != nil { 475 t.Fatal(err) 476 } 477 c.Close() 478 479 // The server should've seen both connections. 480 closed.Wait() 481} 482 483func TestDialerPartialDeadline(t *testing.T) { 484 now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) 485 var testCases = []struct { 486 now time.Time 487 deadline time.Time 488 addrs int 489 expectDeadline time.Time 490 expectErr error 491 }{ 492 // Regular division. 493 {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil}, 494 {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil}, 495 {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil}, 496 // Bump against the 2-second sane minimum. 497 {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil}, 498 // Total available is now below the sane minimum. 499 {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil}, 500 // Null deadline. 501 {now, noDeadline, 1, noDeadline, nil}, 502 // Step the clock forward and cross the deadline. 503 {now.Add(-1 * time.Millisecond), now, 1, now, nil}, 504 {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout}, 505 {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout}, 506 } 507 for i, tt := range testCases { 508 deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) 509 if err != tt.expectErr { 510 t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr) 511 } 512 if !deadline.Equal(tt.expectDeadline) { 513 t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline) 514 } 515 } 516} 517 518// isEADDRINUSE reports whether err is syscall.EADDRINUSE. 519var isEADDRINUSE = func(err error) bool { return false } 520 521func TestDialerLocalAddr(t *testing.T) { 522 if !supportsIPv4() || !supportsIPv6() { 523 t.Skip("both IPv4 and IPv6 are required") 524 } 525 526 type test struct { 527 network, raddr string 528 laddr Addr 529 error 530 } 531 var tests = []test{ 532 {"tcp4", "127.0.0.1", nil, nil}, 533 {"tcp4", "127.0.0.1", &TCPAddr{}, nil}, 534 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 535 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 536 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}}, 537 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, 538 {"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, 539 {"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, 540 {"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, 541 {"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, 542 543 {"tcp6", "::1", nil, nil}, 544 {"tcp6", "::1", &TCPAddr{}, nil}, 545 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 546 {"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 547 {"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, 548 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, 549 {"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, 550 {"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil}, 551 {"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, 552 {"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, 553 554 {"tcp", "127.0.0.1", nil, nil}, 555 {"tcp", "127.0.0.1", &TCPAddr{}, nil}, 556 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 557 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 558 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil}, 559 {"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil}, 560 {"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress}, 561 {"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}}, 562 {"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}}, 563 564 {"tcp", "::1", nil, nil}, 565 {"tcp", "::1", &TCPAddr{}, nil}, 566 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil}, 567 {"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil}, 568 {"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil}, 569 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress}, 570 {"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress}, 571 {"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil}, 572 {"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}}, 573 {"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}}, 574 } 575 576 issue34264Index := -1 577 if supportsIPv4map() { 578 issue34264Index = len(tests) 579 tests = append(tests, test{ 580 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil, 581 }) 582 } else { 583 tests = append(tests, test{ 584 "tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}, 585 }) 586 } 587 588 origTestHookLookupIP := testHookLookupIP 589 defer func() { testHookLookupIP = origTestHookLookupIP }() 590 testHookLookupIP = lookupLocalhost 591 handler := func(ls *localServer, ln Listener) { 592 for { 593 c, err := ln.Accept() 594 if err != nil { 595 return 596 } 597 c.Close() 598 } 599 } 600 var lss [2]*localServer 601 for i, network := range []string{"tcp4", "tcp6"} { 602 lss[i] = newLocalServer(t, network) 603 defer lss[i].teardown() 604 if err := lss[i].buildup(handler); err != nil { 605 t.Fatal(err) 606 } 607 } 608 609 for i, tt := range tests { 610 d := &Dialer{LocalAddr: tt.laddr} 611 var addr string 612 ip := ParseIP(tt.raddr) 613 if ip.To4() != nil { 614 addr = lss[0].Listener.Addr().String() 615 } 616 if ip.To16() != nil && ip.To4() == nil { 617 addr = lss[1].Listener.Addr().String() 618 } 619 c, err := d.Dial(tt.network, addr) 620 if err == nil && tt.error != nil || err != nil && tt.error == nil { 621 if i == issue34264Index && runtime.GOOS == "freebsd" && isEADDRINUSE(err) { 622 // https://golang.org/issue/34264: FreeBSD through at least version 12.2 623 // has been observed to fail with EADDRINUSE when dialing from an IPv6 624 // local address to an IPv4 remote address. 625 t.Logf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error) 626 t.Logf("(spurious EADDRINUSE ignored on freebsd: see https://golang.org/issue/34264)") 627 } else { 628 t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error) 629 } 630 } 631 if err != nil { 632 if perr := parseDialError(err); perr != nil { 633 t.Error(perr) 634 } 635 continue 636 } 637 c.Close() 638 } 639} 640 641func TestDialerDualStack(t *testing.T) { 642 testenv.SkipFlaky(t, 13324) 643 644 if !supportsIPv4() || !supportsIPv6() { 645 t.Skip("both IPv4 and IPv6 are required") 646 } 647 648 closedPortDelay := dialClosedPort(t) 649 650 origTestHookLookupIP := testHookLookupIP 651 defer func() { testHookLookupIP = origTestHookLookupIP }() 652 testHookLookupIP = lookupLocalhost 653 handler := func(dss *dualStackServer, ln Listener) { 654 for { 655 c, err := ln.Accept() 656 if err != nil { 657 return 658 } 659 c.Close() 660 } 661 } 662 663 var timeout = 150*time.Millisecond + closedPortDelay 664 for _, dualstack := range []bool{false, true} { 665 dss, err := newDualStackServer() 666 if err != nil { 667 t.Fatal(err) 668 } 669 defer dss.teardown() 670 if err := dss.buildup(handler); err != nil { 671 t.Fatal(err) 672 } 673 674 d := &Dialer{DualStack: dualstack, Timeout: timeout} 675 for range dss.lns { 676 c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) 677 if err != nil { 678 t.Error(err) 679 continue 680 } 681 switch addr := c.LocalAddr().(*TCPAddr); { 682 case addr.IP.To4() != nil: 683 dss.teardownNetwork("tcp4") 684 case addr.IP.To16() != nil && addr.IP.To4() == nil: 685 dss.teardownNetwork("tcp6") 686 } 687 c.Close() 688 } 689 } 690} 691 692func TestDialerKeepAlive(t *testing.T) { 693 t.Cleanup(func() { 694 testHookSetKeepAlive = func(KeepAliveConfig) {} 695 }) 696 697 handler := func(ls *localServer, ln Listener) { 698 for { 699 c, err := ln.Accept() 700 if err != nil { 701 return 702 } 703 c.Close() 704 } 705 } 706 ln := newLocalListener(t, "tcp", &ListenConfig{ 707 KeepAlive: -1, // prevent calling hook from accepting 708 }) 709 ls := (&streamListener{Listener: ln}).newLocalServer() 710 defer ls.teardown() 711 if err := ls.buildup(handler); err != nil { 712 t.Fatal(err) 713 } 714 715 tests := []struct { 716 ka time.Duration 717 expected time.Duration 718 }{ 719 {-1, -1}, 720 {0, 0}, 721 {5 * time.Second, 5 * time.Second}, 722 {30 * time.Second, 30 * time.Second}, 723 } 724 725 var got time.Duration = -1 726 testHookSetKeepAlive = func(cfg KeepAliveConfig) { got = cfg.Idle } 727 728 for _, test := range tests { 729 got = -1 730 d := Dialer{KeepAlive: test.ka} 731 c, err := d.Dial("tcp", ls.Listener.Addr().String()) 732 if err != nil { 733 t.Fatal(err) 734 } 735 c.Close() 736 if got != test.expected { 737 t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected) 738 } 739 } 740} 741 742func TestDialCancel(t *testing.T) { 743 mustHaveExternalNetwork(t) 744 745 blackholeIPPort := JoinHostPort(slowDst4, "1234") 746 if !supportsIPv4() { 747 blackholeIPPort = JoinHostPort(slowDst6, "1234") 748 } 749 750 ticker := time.NewTicker(10 * time.Millisecond) 751 defer ticker.Stop() 752 753 const cancelTick = 5 // the timer tick we cancel the dial at 754 const timeoutTick = 100 755 756 var d Dialer 757 cancel := make(chan struct{}) 758 d.Cancel = cancel 759 errc := make(chan error, 1) 760 connc := make(chan Conn, 1) 761 go func() { 762 if c, err := d.Dial("tcp", blackholeIPPort); err != nil { 763 errc <- err 764 } else { 765 connc <- c 766 } 767 }() 768 ticks := 0 769 for { 770 select { 771 case <-ticker.C: 772 ticks++ 773 if ticks == cancelTick { 774 close(cancel) 775 } 776 if ticks == timeoutTick { 777 t.Fatal("timeout waiting for dial to fail") 778 } 779 case c := <-connc: 780 c.Close() 781 t.Fatal("unexpected successful connection") 782 case err := <-errc: 783 if perr := parseDialError(err); perr != nil { 784 t.Error(perr) 785 } 786 if ticks < cancelTick { 787 // Using strings.Contains is ugly but 788 // may work on plan9 and windows. 789 ignorable := []string{ 790 "connection refused", 791 "unreachable", 792 "no route to host", 793 "invalid argument", 794 } 795 e := err.Error() 796 for _, ignore := range ignorable { 797 if strings.Contains(e, ignore) { 798 t.Skipf("connection to %v failed fast with %v", blackholeIPPort, err) 799 } 800 } 801 802 t.Fatalf("dial error after %d ticks (%d before cancel sent): %v", 803 ticks, cancelTick-ticks, err) 804 } 805 if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled { 806 t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err) 807 } 808 return // success. 809 } 810 } 811} 812 813func TestCancelAfterDial(t *testing.T) { 814 if testing.Short() { 815 t.Skip("avoiding time.Sleep") 816 } 817 818 ln := newLocalListener(t, "tcp") 819 820 var wg sync.WaitGroup 821 wg.Add(1) 822 defer func() { 823 ln.Close() 824 wg.Wait() 825 }() 826 827 // Echo back the first line of each incoming connection. 828 go func() { 829 for { 830 c, err := ln.Accept() 831 if err != nil { 832 break 833 } 834 rb := bufio.NewReader(c) 835 line, err := rb.ReadString('\n') 836 if err != nil { 837 t.Error(err) 838 c.Close() 839 continue 840 } 841 if _, err := c.Write([]byte(line)); err != nil { 842 t.Error(err) 843 } 844 c.Close() 845 } 846 wg.Done() 847 }() 848 849 try := func() { 850 cancel := make(chan struct{}) 851 d := &Dialer{Cancel: cancel} 852 c, err := d.Dial("tcp", ln.Addr().String()) 853 854 // Immediately after dialing, request cancellation and sleep. 855 // Before Issue 15078 was fixed, this would cause subsequent operations 856 // to fail with an i/o timeout roughly 50% of the time. 857 close(cancel) 858 time.Sleep(10 * time.Millisecond) 859 860 if err != nil { 861 t.Fatal(err) 862 } 863 defer c.Close() 864 865 // Send some data to confirm that the connection is still alive. 866 const message = "echo!\n" 867 if _, err := c.Write([]byte(message)); err != nil { 868 t.Fatal(err) 869 } 870 871 // The server should echo the line, and close the connection. 872 rb := bufio.NewReader(c) 873 line, err := rb.ReadString('\n') 874 if err != nil { 875 t.Fatal(err) 876 } 877 if line != message { 878 t.Errorf("got %q; want %q", line, message) 879 } 880 if _, err := rb.ReadByte(); err != io.EOF { 881 t.Errorf("got %v; want %v", err, io.EOF) 882 } 883 } 884 885 // This bug manifested about 50% of the time, so try it a few times. 886 for i := 0; i < 10; i++ { 887 try() 888 } 889} 890 891func TestDialClosedPortFailFast(t *testing.T) { 892 if runtime.GOOS != "windows" { 893 // Reported by go.dev/issues/23366. 894 t.Skip("skipping windows only test") 895 } 896 for _, network := range []string{"tcp", "tcp4", "tcp6"} { 897 t.Run(network, func(t *testing.T) { 898 if !testableNetwork(network) { 899 t.Skipf("skipping: can't listen on %s", network) 900 } 901 // Reserve a local port till the end of the 902 // test by opening a listener and connecting to 903 // it using Dial. 904 ln := newLocalListener(t, network) 905 addr := ln.Addr().String() 906 conn1, err := Dial(network, addr) 907 if err != nil { 908 ln.Close() 909 t.Fatal(err) 910 } 911 defer conn1.Close() 912 // Now close the listener so the next Dial fails 913 // keeping conn1 alive so the port is not made 914 // available. 915 ln.Close() 916 917 maxElapsed := time.Second 918 // The host can be heavy-loaded and take 919 // longer than configured. Retry until 920 // Dial takes less than maxElapsed or 921 // the test times out. 922 for { 923 startTime := time.Now() 924 conn2, err := Dial(network, addr) 925 if err == nil { 926 conn2.Close() 927 t.Fatal("error expected") 928 } 929 elapsed := time.Since(startTime) 930 if elapsed < maxElapsed { 931 break 932 } 933 t.Logf("got %v; want < %v", elapsed, maxElapsed) 934 } 935 }) 936 } 937} 938 939// Issue 18806: it should always be possible to net.Dial a 940// net.Listener().Addr().String when the listen address was ":n", even 941// if the machine has halfway configured IPv6 such that it can bind on 942// "::" not connect back to that same address. 943func TestDialListenerAddr(t *testing.T) { 944 if !testableNetwork("tcp4") { 945 t.Skipf("skipping: can't listen on tcp4") 946 } 947 948 // The original issue report was for listening on just ":0" on a system that 949 // supports both tcp4 and tcp6 for external traffic but only tcp4 for loopback 950 // traffic. However, the port opened by ":0" is externally-accessible, and may 951 // trigger firewall alerts or otherwise be mistaken for malicious activity 952 // (see https://go.dev/issue/59497). Moreover, it often does not reproduce 953 // the scenario in the issue, in which the port *cannot* be dialed as tcp6. 954 // 955 // To address both of those problems, we open a tcp4-only localhost port, but 956 // then dial the address string that the listener would have reported for a 957 // dual-stack port. 958 ln, err := Listen("tcp4", "localhost:0") 959 if err != nil { 960 t.Fatal(err) 961 } 962 defer ln.Close() 963 964 t.Logf("listening on %q", ln.Addr()) 965 _, port, err := SplitHostPort(ln.Addr().String()) 966 if err != nil { 967 t.Fatal(err) 968 } 969 970 // If we had opened a dual-stack port without an explicit "localhost" address, 971 // the Listener would arbitrarily report an empty tcp6 address in its Addr 972 // string. 973 // 974 // The documentation for Dial says ‘if the host is empty or a literal 975 // unspecified IP address, as in ":80", "0.0.0.0:80" or "[::]:80" for TCP and 976 // UDP, "", "0.0.0.0" or "::" for IP, the local system is assumed.’ 977 // In #18806, it was decided that that should include the local tcp4 host 978 // even if the string is in the tcp6 format. 979 dialAddr := "[::]:" + port 980 c, err := Dial("tcp4", dialAddr) 981 if err != nil { 982 t.Fatalf(`Dial("tcp4", %q): %v`, dialAddr, err) 983 } 984 c.Close() 985 t.Logf(`Dial("tcp4", %q) succeeded`, dialAddr) 986} 987 988func TestDialerControl(t *testing.T) { 989 switch runtime.GOOS { 990 case "plan9": 991 t.Skipf("not supported on %s", runtime.GOOS) 992 case "js", "wasip1": 993 t.Skipf("skipping: fake net does not support Dialer.Control") 994 } 995 996 t.Run("StreamDial", func(t *testing.T) { 997 for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} { 998 if !testableNetwork(network) { 999 continue 1000 } 1001 ln := newLocalListener(t, network) 1002 defer ln.Close() 1003 d := Dialer{Control: controlOnConnSetup} 1004 c, err := d.Dial(network, ln.Addr().String()) 1005 if err != nil { 1006 t.Error(err) 1007 continue 1008 } 1009 c.Close() 1010 } 1011 }) 1012 t.Run("PacketDial", func(t *testing.T) { 1013 for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} { 1014 if !testableNetwork(network) { 1015 continue 1016 } 1017 c1 := newLocalPacketListener(t, network) 1018 if network == "unixgram" { 1019 defer os.Remove(c1.LocalAddr().String()) 1020 } 1021 defer c1.Close() 1022 d := Dialer{Control: controlOnConnSetup} 1023 c2, err := d.Dial(network, c1.LocalAddr().String()) 1024 if err != nil { 1025 t.Error(err) 1026 continue 1027 } 1028 c2.Close() 1029 } 1030 }) 1031} 1032 1033func TestDialerControlContext(t *testing.T) { 1034 switch runtime.GOOS { 1035 case "plan9": 1036 t.Skipf("%s does not have full support of socktest", runtime.GOOS) 1037 case "js", "wasip1": 1038 t.Skipf("skipping: fake net does not support Dialer.ControlContext") 1039 } 1040 t.Run("StreamDial", func(t *testing.T) { 1041 for i, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} { 1042 t.Run(network, func(t *testing.T) { 1043 if !testableNetwork(network) { 1044 t.Skipf("skipping: %s not available", network) 1045 } 1046 1047 ln := newLocalListener(t, network) 1048 defer ln.Close() 1049 var id int 1050 d := Dialer{ControlContext: func(ctx context.Context, network string, address string, c syscall.RawConn) error { 1051 id = ctx.Value("id").(int) 1052 return controlOnConnSetup(network, address, c) 1053 }} 1054 c, err := d.DialContext(context.WithValue(context.Background(), "id", i+1), network, ln.Addr().String()) 1055 if err != nil { 1056 t.Fatal(err) 1057 } 1058 if id != i+1 { 1059 t.Errorf("got id %d, want %d", id, i+1) 1060 } 1061 c.Close() 1062 }) 1063 } 1064 }) 1065} 1066 1067// mustHaveExternalNetwork is like testenv.MustHaveExternalNetwork 1068// except on non-Linux, non-mobile builders it permits the test to 1069// run in -short mode. 1070func mustHaveExternalNetwork(t *testing.T) { 1071 t.Helper() 1072 definitelyHasLongtestBuilder := runtime.GOOS == "linux" 1073 mobile := runtime.GOOS == "android" || runtime.GOOS == "ios" 1074 fake := runtime.GOOS == "js" || runtime.GOOS == "wasip1" 1075 if testenv.Builder() != "" && !definitelyHasLongtestBuilder && !mobile && !fake { 1076 // On a non-Linux, non-mobile builder (e.g., freebsd-amd64-13_0). 1077 // 1078 // Don't skip testing because otherwise the test may never run on 1079 // any builder if this port doesn't also have a -longtest builder. 1080 return 1081 } 1082 testenv.MustHaveExternalNetwork(t) 1083} 1084 1085type contextWithNonZeroDeadline struct { 1086 context.Context 1087} 1088 1089func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) { 1090 // Return non-zero time.Time value with false indicating that no deadline is set. 1091 return time.Unix(0, 0), false 1092} 1093 1094func TestDialWithNonZeroDeadline(t *testing.T) { 1095 ln := newLocalListener(t, "tcp") 1096 defer ln.Close() 1097 _, port, err := SplitHostPort(ln.Addr().String()) 1098 if err != nil { 1099 t.Fatal(err) 1100 } 1101 1102 ctx := contextWithNonZeroDeadline{Context: context.Background()} 1103 var dialer Dialer 1104 c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port)) 1105 if err != nil { 1106 t.Fatal(err) 1107 } 1108 c.Close() 1109} 1110