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

View as plain text