mirror of
https://github.com/coder/coder.git
synced 2025-07-13 21:36:50 +00:00
feat: change port-forward to opportunistically listen on IPv6 (#15640)
If the local IP address is not explicitly set, previously we assumed 127.0.0.1 (that is, IPv4 only localhost). This PR adds support to opportunistically _also_ listen on IPv6 ::1.
This commit is contained in:
@ -67,6 +67,17 @@ func TestPortForward(t *testing.T) {
|
||||
},
|
||||
localAddress: []string{"127.0.0.1:5555", "127.0.0.1:6666"},
|
||||
},
|
||||
{
|
||||
name: "TCP-opportunistic-ipv6",
|
||||
network: "tcp",
|
||||
flag: []string{"--tcp=5566:%v", "--tcp=6655:%v"},
|
||||
setupRemote: func(t *testing.T) net.Listener {
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err, "create TCP listener")
|
||||
return l
|
||||
},
|
||||
localAddress: []string{"[::1]:5566", "[::1]:6655"},
|
||||
},
|
||||
{
|
||||
name: "UDP",
|
||||
network: "udp",
|
||||
@ -82,6 +93,21 @@ func TestPortForward(t *testing.T) {
|
||||
},
|
||||
localAddress: []string{"127.0.0.1:7777", "127.0.0.1:8888"},
|
||||
},
|
||||
{
|
||||
name: "UDP-opportunistic-ipv6",
|
||||
network: "udp",
|
||||
flag: []string{"--udp=7788:%v", "--udp=8877:%v"},
|
||||
setupRemote: func(t *testing.T) net.Listener {
|
||||
addr := net.UDPAddr{
|
||||
IP: net.ParseIP("127.0.0.1"),
|
||||
Port: 0,
|
||||
}
|
||||
l, err := udp.Listen("udp", &addr)
|
||||
require.NoError(t, err, "create UDP listener")
|
||||
return l
|
||||
},
|
||||
localAddress: []string{"[::1]:7788", "[::1]:8877"},
|
||||
},
|
||||
{
|
||||
name: "TCPWithAddress",
|
||||
network: "tcp", flag: []string{"--tcp=10.10.10.99:9999:%v", "--tcp=10.10.10.10:1010:%v"},
|
||||
@ -295,6 +321,63 @@ func TestPortForward(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, updated.LastUsedAt, workspace.LastUsedAt)
|
||||
})
|
||||
|
||||
t.Run("IPv6Busy", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
remoteLis, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
require.NoError(t, err, "create TCP listener")
|
||||
p1 := setupTestListener(t, remoteLis)
|
||||
|
||||
// Create a flag that forwards from local 5555 to remote listener port.
|
||||
flag := fmt.Sprintf("--tcp=5555:%v", p1)
|
||||
|
||||
// Launch port-forward in a goroutine so we can start dialing
|
||||
// the "local" listener.
|
||||
inv, root := clitest.New(t, "-v", "port-forward", workspace.Name, flag)
|
||||
clitest.SetupConfig(t, member, root)
|
||||
pty := ptytest.New(t)
|
||||
inv.Stdin = pty.Input()
|
||||
inv.Stdout = pty.Output()
|
||||
inv.Stderr = pty.Output()
|
||||
|
||||
iNet := newInProcNet()
|
||||
inv.Net = iNet
|
||||
|
||||
// listen on port 5555 on IPv6 so it's busy when we try to port forward
|
||||
busyLis, err := iNet.Listen("tcp", "[::1]:5555")
|
||||
require.NoError(t, err)
|
||||
defer busyLis.Close()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
|
||||
defer cancel()
|
||||
errC := make(chan error)
|
||||
go func() {
|
||||
err := inv.WithContext(ctx).Run()
|
||||
t.Logf("command complete; err=%s", err.Error())
|
||||
errC <- err
|
||||
}()
|
||||
pty.ExpectMatchContext(ctx, "Ready!")
|
||||
|
||||
// Test IPv4 still works
|
||||
dialCtx, dialCtxCancel := context.WithTimeout(ctx, testutil.WaitShort)
|
||||
defer dialCtxCancel()
|
||||
c1, err := iNet.dial(dialCtx, addr{"tcp", "127.0.0.1:5555"})
|
||||
require.NoError(t, err, "open connection 1 to 'local' listener")
|
||||
defer c1.Close()
|
||||
testDial(t, c1)
|
||||
|
||||
cancel()
|
||||
err = <-errC
|
||||
require.ErrorIs(t, err, context.Canceled)
|
||||
|
||||
flushCtx := testutil.Context(t, testutil.WaitShort)
|
||||
testutil.RequireSendCtx(flushCtx, t, wuTick, dbtime.Now())
|
||||
_ = testutil.RequireRecvCtx(flushCtx, t, wuFlush)
|
||||
updated, err := client.Workspace(context.Background(), workspace.ID)
|
||||
require.NoError(t, err)
|
||||
require.Greater(t, updated.LastUsedAt, workspace.LastUsedAt)
|
||||
})
|
||||
}
|
||||
|
||||
// runAgent creates a fake workspace and starts an agent locally for that
|
||||
|
Reference in New Issue
Block a user