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