Source file src/net/dial_test.go

     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  
     5  package net
     6  
     7  import (
     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  
    23  var prohibitionaryDialArgTests = []struct {
    24  	network string
    25  	address string
    26  }{
    27  	{"tcp6", "127.0.0.1"},
    28  	{"tcp6", "::ffff:127.0.0.1"},
    29  }
    30  
    31  func 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  
    62  func 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  
    76  func 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.
   137  const (
   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.
   145  func 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  
   155  func 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  
   178  func 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  
   304  func 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  
   317  func 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  
   385  func 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  
   483  func 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.
   519  var isEADDRINUSE = func(err error) bool { return false }
   520  
   521  func 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  
   641  func 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  
   692  func TestDialerKeepAlive(t *testing.T) {
   693  	handler := func(ls *localServer, ln Listener) {
   694  		for {
   695  			c, err := ln.Accept()
   696  			if err != nil {
   697  				return
   698  			}
   699  			c.Close()
   700  		}
   701  	}
   702  	ls := newLocalServer(t, "tcp")
   703  	defer ls.teardown()
   704  	if err := ls.buildup(handler); err != nil {
   705  		t.Fatal(err)
   706  	}
   707  	defer func() { testHookSetKeepAlive = func(time.Duration) {} }()
   708  
   709  	tests := []struct {
   710  		ka       time.Duration
   711  		expected time.Duration
   712  	}{
   713  		{-1, -1},
   714  		{0, 15 * time.Second},
   715  		{5 * time.Second, 5 * time.Second},
   716  		{30 * time.Second, 30 * time.Second},
   717  	}
   718  
   719  	for _, test := range tests {
   720  		var got time.Duration = -1
   721  		testHookSetKeepAlive = func(d time.Duration) { got = d }
   722  		d := Dialer{KeepAlive: test.ka}
   723  		c, err := d.Dial("tcp", ls.Listener.Addr().String())
   724  		if err != nil {
   725  			t.Fatal(err)
   726  		}
   727  		c.Close()
   728  		if got != test.expected {
   729  			t.Errorf("Dialer.KeepAlive = %v: SetKeepAlive set to %v, want %v", d.KeepAlive, got, test.expected)
   730  		}
   731  	}
   732  }
   733  
   734  func TestDialCancel(t *testing.T) {
   735  	mustHaveExternalNetwork(t)
   736  
   737  	blackholeIPPort := JoinHostPort(slowDst4, "1234")
   738  	if !supportsIPv4() {
   739  		blackholeIPPort = JoinHostPort(slowDst6, "1234")
   740  	}
   741  
   742  	ticker := time.NewTicker(10 * time.Millisecond)
   743  	defer ticker.Stop()
   744  
   745  	const cancelTick = 5 // the timer tick we cancel the dial at
   746  	const timeoutTick = 100
   747  
   748  	var d Dialer
   749  	cancel := make(chan struct{})
   750  	d.Cancel = cancel
   751  	errc := make(chan error, 1)
   752  	connc := make(chan Conn, 1)
   753  	go func() {
   754  		if c, err := d.Dial("tcp", blackholeIPPort); err != nil {
   755  			errc <- err
   756  		} else {
   757  			connc <- c
   758  		}
   759  	}()
   760  	ticks := 0
   761  	for {
   762  		select {
   763  		case <-ticker.C:
   764  			ticks++
   765  			if ticks == cancelTick {
   766  				close(cancel)
   767  			}
   768  			if ticks == timeoutTick {
   769  				t.Fatal("timeout waiting for dial to fail")
   770  			}
   771  		case c := <-connc:
   772  			c.Close()
   773  			t.Fatal("unexpected successful connection")
   774  		case err := <-errc:
   775  			if perr := parseDialError(err); perr != nil {
   776  				t.Error(perr)
   777  			}
   778  			if ticks < cancelTick {
   779  				// Using strings.Contains is ugly but
   780  				// may work on plan9 and windows.
   781  				ignorable := []string{
   782  					"connection refused",
   783  					"unreachable",
   784  					"no route to host",
   785  					"invalid argument",
   786  				}
   787  				e := err.Error()
   788  				for _, ignore := range ignorable {
   789  					if strings.Contains(e, ignore) {
   790  						t.Skipf("connection to %v failed fast with %v", blackholeIPPort, err)
   791  					}
   792  				}
   793  
   794  				t.Fatalf("dial error after %d ticks (%d before cancel sent): %v",
   795  					ticks, cancelTick-ticks, err)
   796  			}
   797  			if oe, ok := err.(*OpError); !ok || oe.Err != errCanceled {
   798  				t.Fatalf("dial error = %v (%T); want OpError with Err == errCanceled", err, err)
   799  			}
   800  			return // success.
   801  		}
   802  	}
   803  }
   804  
   805  func TestCancelAfterDial(t *testing.T) {
   806  	if testing.Short() {
   807  		t.Skip("avoiding time.Sleep")
   808  	}
   809  
   810  	ln := newLocalListener(t, "tcp")
   811  
   812  	var wg sync.WaitGroup
   813  	wg.Add(1)
   814  	defer func() {
   815  		ln.Close()
   816  		wg.Wait()
   817  	}()
   818  
   819  	// Echo back the first line of each incoming connection.
   820  	go func() {
   821  		for {
   822  			c, err := ln.Accept()
   823  			if err != nil {
   824  				break
   825  			}
   826  			rb := bufio.NewReader(c)
   827  			line, err := rb.ReadString('\n')
   828  			if err != nil {
   829  				t.Error(err)
   830  				c.Close()
   831  				continue
   832  			}
   833  			if _, err := c.Write([]byte(line)); err != nil {
   834  				t.Error(err)
   835  			}
   836  			c.Close()
   837  		}
   838  		wg.Done()
   839  	}()
   840  
   841  	try := func() {
   842  		cancel := make(chan struct{})
   843  		d := &Dialer{Cancel: cancel}
   844  		c, err := d.Dial("tcp", ln.Addr().String())
   845  
   846  		// Immediately after dialing, request cancellation and sleep.
   847  		// Before Issue 15078 was fixed, this would cause subsequent operations
   848  		// to fail with an i/o timeout roughly 50% of the time.
   849  		close(cancel)
   850  		time.Sleep(10 * time.Millisecond)
   851  
   852  		if err != nil {
   853  			t.Fatal(err)
   854  		}
   855  		defer c.Close()
   856  
   857  		// Send some data to confirm that the connection is still alive.
   858  		const message = "echo!\n"
   859  		if _, err := c.Write([]byte(message)); err != nil {
   860  			t.Fatal(err)
   861  		}
   862  
   863  		// The server should echo the line, and close the connection.
   864  		rb := bufio.NewReader(c)
   865  		line, err := rb.ReadString('\n')
   866  		if err != nil {
   867  			t.Fatal(err)
   868  		}
   869  		if line != message {
   870  			t.Errorf("got %q; want %q", line, message)
   871  		}
   872  		if _, err := rb.ReadByte(); err != io.EOF {
   873  			t.Errorf("got %v; want %v", err, io.EOF)
   874  		}
   875  	}
   876  
   877  	// This bug manifested about 50% of the time, so try it a few times.
   878  	for i := 0; i < 10; i++ {
   879  		try()
   880  	}
   881  }
   882  
   883  func TestDialClosedPortFailFast(t *testing.T) {
   884  	if runtime.GOOS != "windows" {
   885  		// Reported by go.dev/issues/23366.
   886  		t.Skip("skipping windows only test")
   887  	}
   888  	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
   889  		t.Run(network, func(t *testing.T) {
   890  			if !testableNetwork(network) {
   891  				t.Skipf("skipping: can't listen on %s", network)
   892  			}
   893  			// Reserve a local port till the end of the
   894  			// test by opening a listener and connecting to
   895  			// it using Dial.
   896  			ln := newLocalListener(t, network)
   897  			addr := ln.Addr().String()
   898  			conn1, err := Dial(network, addr)
   899  			if err != nil {
   900  				ln.Close()
   901  				t.Fatal(err)
   902  			}
   903  			defer conn1.Close()
   904  			// Now close the listener so the next Dial fails
   905  			// keeping conn1 alive so the port is not made
   906  			// available.
   907  			ln.Close()
   908  
   909  			maxElapsed := time.Second
   910  			// The host can be heavy-loaded and take
   911  			// longer than configured. Retry until
   912  			// Dial takes less than maxElapsed or
   913  			// the test times out.
   914  			for {
   915  				startTime := time.Now()
   916  				conn2, err := Dial(network, addr)
   917  				if err == nil {
   918  					conn2.Close()
   919  					t.Fatal("error expected")
   920  				}
   921  				elapsed := time.Since(startTime)
   922  				if elapsed < maxElapsed {
   923  					break
   924  				}
   925  				t.Logf("got %v; want < %v", elapsed, maxElapsed)
   926  			}
   927  		})
   928  	}
   929  }
   930  
   931  // Issue 18806: it should always be possible to net.Dial a
   932  // net.Listener().Addr().String when the listen address was ":n", even
   933  // if the machine has halfway configured IPv6 such that it can bind on
   934  // "::" not connect back to that same address.
   935  func TestDialListenerAddr(t *testing.T) {
   936  	if !testableNetwork("tcp4") {
   937  		t.Skipf("skipping: can't listen on tcp4")
   938  	}
   939  
   940  	// The original issue report was for listening on just ":0" on a system that
   941  	// supports both tcp4 and tcp6 for external traffic but only tcp4 for loopback
   942  	// traffic. However, the port opened by ":0" is externally-accessible, and may
   943  	// trigger firewall alerts or otherwise be mistaken for malicious activity
   944  	// (see https://go.dev/issue/59497). Moreover, it often does not reproduce
   945  	// the scenario in the issue, in which the port *cannot* be dialed as tcp6.
   946  	//
   947  	// To address both of those problems, we open a tcp4-only localhost port, but
   948  	// then dial the address string that the listener would have reported for a
   949  	// dual-stack port.
   950  	ln, err := Listen("tcp4", "localhost:0")
   951  	if err != nil {
   952  		t.Fatal(err)
   953  	}
   954  	defer ln.Close()
   955  
   956  	t.Logf("listening on %q", ln.Addr())
   957  	_, port, err := SplitHostPort(ln.Addr().String())
   958  	if err != nil {
   959  		t.Fatal(err)
   960  	}
   961  
   962  	// If we had opened a dual-stack port without an explicit "localhost" address,
   963  	// the Listener would arbitrarily report an empty tcp6 address in its Addr
   964  	// string.
   965  	//
   966  	// The documentation for Dial says ‘if the host is empty or a literal
   967  	// unspecified IP address, as in ":80", "0.0.0.0:80" or "[::]:80" for TCP and
   968  	// UDP, "", "0.0.0.0" or "::" for IP, the local system is assumed.’
   969  	// In #18806, it was decided that that should include the local tcp4 host
   970  	// even if the string is in the tcp6 format.
   971  	dialAddr := "[::]:" + port
   972  	c, err := Dial("tcp4", dialAddr)
   973  	if err != nil {
   974  		t.Fatalf(`Dial("tcp4", %q): %v`, dialAddr, err)
   975  	}
   976  	c.Close()
   977  	t.Logf(`Dial("tcp4", %q) succeeded`, dialAddr)
   978  }
   979  
   980  func TestDialerControl(t *testing.T) {
   981  	switch runtime.GOOS {
   982  	case "plan9":
   983  		t.Skipf("not supported on %s", runtime.GOOS)
   984  	case "js", "wasip1":
   985  		t.Skipf("skipping: fake net does not support Dialer.Control")
   986  	}
   987  
   988  	t.Run("StreamDial", func(t *testing.T) {
   989  		for _, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
   990  			if !testableNetwork(network) {
   991  				continue
   992  			}
   993  			ln := newLocalListener(t, network)
   994  			defer ln.Close()
   995  			d := Dialer{Control: controlOnConnSetup}
   996  			c, err := d.Dial(network, ln.Addr().String())
   997  			if err != nil {
   998  				t.Error(err)
   999  				continue
  1000  			}
  1001  			c.Close()
  1002  		}
  1003  	})
  1004  	t.Run("PacketDial", func(t *testing.T) {
  1005  		for _, network := range []string{"udp", "udp4", "udp6", "unixgram"} {
  1006  			if !testableNetwork(network) {
  1007  				continue
  1008  			}
  1009  			c1 := newLocalPacketListener(t, network)
  1010  			if network == "unixgram" {
  1011  				defer os.Remove(c1.LocalAddr().String())
  1012  			}
  1013  			defer c1.Close()
  1014  			d := Dialer{Control: controlOnConnSetup}
  1015  			c2, err := d.Dial(network, c1.LocalAddr().String())
  1016  			if err != nil {
  1017  				t.Error(err)
  1018  				continue
  1019  			}
  1020  			c2.Close()
  1021  		}
  1022  	})
  1023  }
  1024  
  1025  func TestDialerControlContext(t *testing.T) {
  1026  	switch runtime.GOOS {
  1027  	case "plan9":
  1028  		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
  1029  	case "js", "wasip1":
  1030  		t.Skipf("skipping: fake net does not support Dialer.ControlContext")
  1031  	}
  1032  	t.Run("StreamDial", func(t *testing.T) {
  1033  		for i, network := range []string{"tcp", "tcp4", "tcp6", "unix", "unixpacket"} {
  1034  			t.Run(network, func(t *testing.T) {
  1035  				if !testableNetwork(network) {
  1036  					t.Skipf("skipping: %s not available", network)
  1037  				}
  1038  
  1039  				ln := newLocalListener(t, network)
  1040  				defer ln.Close()
  1041  				var id int
  1042  				d := Dialer{ControlContext: func(ctx context.Context, network string, address string, c syscall.RawConn) error {
  1043  					id = ctx.Value("id").(int)
  1044  					return controlOnConnSetup(network, address, c)
  1045  				}}
  1046  				c, err := d.DialContext(context.WithValue(context.Background(), "id", i+1), network, ln.Addr().String())
  1047  				if err != nil {
  1048  					t.Fatal(err)
  1049  				}
  1050  				if id != i+1 {
  1051  					t.Errorf("got id %d, want %d", id, i+1)
  1052  				}
  1053  				c.Close()
  1054  			})
  1055  		}
  1056  	})
  1057  }
  1058  
  1059  // mustHaveExternalNetwork is like testenv.MustHaveExternalNetwork
  1060  // except on non-Linux, non-mobile builders it permits the test to
  1061  // run in -short mode.
  1062  func mustHaveExternalNetwork(t *testing.T) {
  1063  	t.Helper()
  1064  	definitelyHasLongtestBuilder := runtime.GOOS == "linux"
  1065  	mobile := runtime.GOOS == "android" || runtime.GOOS == "ios"
  1066  	fake := runtime.GOOS == "js" || runtime.GOOS == "wasip1"
  1067  	if testenv.Builder() != "" && !definitelyHasLongtestBuilder && !mobile && !fake {
  1068  		// On a non-Linux, non-mobile builder (e.g., freebsd-amd64-13_0).
  1069  		//
  1070  		// Don't skip testing because otherwise the test may never run on
  1071  		// any builder if this port doesn't also have a -longtest builder.
  1072  		return
  1073  	}
  1074  	testenv.MustHaveExternalNetwork(t)
  1075  }
  1076  
  1077  type contextWithNonZeroDeadline struct {
  1078  	context.Context
  1079  }
  1080  
  1081  func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) {
  1082  	// Return non-zero time.Time value with false indicating that no deadline is set.
  1083  	return time.Unix(0, 0), false
  1084  }
  1085  
  1086  func TestDialWithNonZeroDeadline(t *testing.T) {
  1087  	ln := newLocalListener(t, "tcp")
  1088  	defer ln.Close()
  1089  	_, port, err := SplitHostPort(ln.Addr().String())
  1090  	if err != nil {
  1091  		t.Fatal(err)
  1092  	}
  1093  
  1094  	ctx := contextWithNonZeroDeadline{Context: context.Background()}
  1095  	var dialer Dialer
  1096  	c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port))
  1097  	if err != nil {
  1098  		t.Fatal(err)
  1099  	}
  1100  	c.Close()
  1101  }
  1102  

View as plain text