From 9621cb802559e9cfc01b080c1d9379d67d7cfa85 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Mon, 22 May 2023 20:49:46 +0000 Subject: [PATCH 1/3] feat(cli): allow specifying the listen address in `coder port-forward` --- cli/portforward.go | 63 +++++++++++++++++++++++++++++++---------- cli/portforward_test.go | 19 +++++++++++++ 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/cli/portforward.go b/cli/portforward.go index dad82381bfb5b..dad19bf866d3a 100644 --- a/cli/portforward.go +++ b/cli/portforward.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net" + "net/netip" "os" "os/signal" "strconv" @@ -47,6 +48,10 @@ func (r *RootCmd) portForward() *clibase.Cmd { Description: "Port forward multiple ports (TCP or UDP) in condensed syntax", Command: "coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012", }, + example{ + Description: "Port forward specifying the local address to bind to", + Command: "coder port-forward --tcp 1.2.3.4:8080:8080", + }, ), Middleware: clibase.Chain( clibase.RequireNArgs(1), @@ -255,9 +260,9 @@ func parsePortForwards(tcpSpecs, udpSpecs []string) ([]portForwardSpec, error) { for _, port := range ports { specs = append(specs, portForwardSpec{ listenNetwork: "tcp", - listenAddress: fmt.Sprintf("127.0.0.1:%v", port.local), + listenAddress: port.local.String(), dialNetwork: "tcp", - dialAddress: fmt.Sprintf("127.0.0.1:%v", port.remote), + dialAddress: port.remote.String(), }) } } @@ -273,9 +278,9 @@ func parsePortForwards(tcpSpecs, udpSpecs []string) ([]portForwardSpec, error) { for _, port := range ports { specs = append(specs, portForwardSpec{ listenNetwork: "udp", - listenAddress: fmt.Sprintf("127.0.0.1:%v", port.local), + listenAddress: port.local.String(), dialNetwork: "udp", - dialAddress: fmt.Sprintf("127.0.0.1:%v", port.remote), + dialAddress: port.remote.String(), }) } } @@ -307,29 +312,57 @@ func parsePort(in string) (uint16, error) { } type parsedSrcDestPort struct { - local, remote uint16 + local, remote netip.AddrPort } func parseSrcDestPorts(in string) ([]parsedSrcDestPort, error) { - parts := strings.Split(in, ":") - if len(parts) > 2 { - return nil, xerrors.Errorf("invalid port specification %q", in) - } - if len(parts) == 1 { + var ( + err error + parts = strings.Split(in, ":") + localAddr = netip.AddrFrom4([4]byte{127, 0, 0, 1}) + remoteAddr = netip.AddrFrom4([4]byte{127, 0, 0, 1}) + ) + + switch len(parts) { + case 1: // Duplicate the single part parts = append(parts, parts[0]) + case 2: + // Check to see if the first part is an IP address. + _localAddr, err := netip.ParseAddr(parts[0]) + if err != nil { + break + } + // The first part is the local address, so duplicate the port. + localAddr = _localAddr + parts = []string{parts[1], parts[1]} + + case 3: + _localAddr, err := netip.ParseAddr(parts[0]) + if err != nil { + return nil, xerrors.Errorf("invalid port specification %q; invalid ip %q: %w", in, parts[0], err) + } + localAddr = _localAddr + parts = parts[1:] + + default: + return nil, xerrors.Errorf("invalid port specification %q", in) } + if !strings.Contains(parts[0], "-") { - local, err := parsePort(parts[0]) + localPort, err := parsePort(parts[0]) if err != nil { return nil, xerrors.Errorf("parse local port from %q: %w", in, err) } - remote, err := parsePort(parts[1]) + remotePort, err := parsePort(parts[1]) if err != nil { return nil, xerrors.Errorf("parse remote port from %q: %w", in, err) } - return []parsedSrcDestPort{{local: local, remote: remote}}, nil + return []parsedSrcDestPort{{ + local: netip.AddrPortFrom(localAddr, localPort), + remote: netip.AddrPortFrom(remoteAddr, remotePort), + }}, nil } local, err := parsePortRange(parts[0]) @@ -346,8 +379,8 @@ func parseSrcDestPorts(in string) ([]parsedSrcDestPort, error) { var out []parsedSrcDestPort for i := range local { out = append(out, parsedSrcDestPort{ - local: local[i], - remote: remote[i], + local: netip.AddrPortFrom(localAddr, local[i]), + remote: netip.AddrPortFrom(netip.IPv4Unspecified(), remote[i]), }) } return out, nil diff --git a/cli/portforward_test.go b/cli/portforward_test.go index c73788725a67d..5ae1997285ab7 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -104,6 +104,25 @@ func TestPortForward(t *testing.T) { return l.Addr().String(), port }, }, + { + name: "TCPWithAddress", + network: "tcp", + flag: "--tcp=%v:%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 + }, + setupLocal: func(t *testing.T) (string, string) { + l, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err, "create TCP listener to generate random port") + defer l.Close() + + _, port, err := net.SplitHostPort(l.Addr().String()) + require.NoErrorf(t, err, "split TCP address %q", l.Addr().String()) + return l.Addr().String(), fmt.Sprint("0.0.0.0:", port) + }, + }, } // Setup agent once to be shared between test-cases (avoid expensive From ae1aeaa5a134b1b4e54360c17cbe458f166fde32 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Mon, 22 May 2023 21:19:14 +0000 Subject: [PATCH 2/3] fixup! feat(cli): allow specifying the listen address in `coder port-forward` --- cli/testdata/coder_port-forward_--help.golden | 4 ++++ docs/cli/port-forward.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/cli/testdata/coder_port-forward_--help.golden b/cli/testdata/coder_port-forward_--help.golden index fd87e6b4fbe2d..6efd95c0e89cf 100644 --- a/cli/testdata/coder_port-forward_--help.golden +++ b/cli/testdata/coder_port-forward_--help.golden @@ -22,6 +22,10 @@ Aliases: tunnel  $ coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012  + - Port forward specifying the local address to bind to: + +  $ coder port-forward --tcp 1.2.3.4:8080:8080  + Options -p, --tcp string-array, $CODER_PORT_FORWARD_TCP Forward TCP port(s) from the workspace to the local machine. diff --git a/docs/cli/port-forward.md b/docs/cli/port-forward.md index 9a79ebc29cf68..5c3ac14c1b126 100644 --- a/docs/cli/port-forward.md +++ b/docs/cli/port-forward.md @@ -34,6 +34,10 @@ coder port-forward [flags] - Port forward multiple ports (TCP or UDP) in condensed syntax: $ coder port-forward --tcp 8080,9000:3000,9090-9092,10000-10002:10010-10012 + + - Port forward specifying the local address to bind to: + + $ coder port-forward --tcp 1.2.3.4:8080:8080 ``` ## Options From 451ccc6fbc4e7c3f1649f6f3fdeebe73c346f391 Mon Sep 17 00:00:00 2001 From: Colin Adler Date: Tue, 23 May 2023 02:02:18 +0000 Subject: [PATCH 3/3] fixup! feat(cli): allow specifying the listen address in `coder port-forward` --- cli/portforward.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/portforward.go b/cli/portforward.go index dad19bf866d3a..fd0f2bcfab57f 100644 --- a/cli/portforward.go +++ b/cli/portforward.go @@ -380,7 +380,7 @@ func parseSrcDestPorts(in string) ([]parsedSrcDestPort, error) { for i := range local { out = append(out, parsedSrcDestPort{ local: netip.AddrPortFrom(localAddr, local[i]), - remote: netip.AddrPortFrom(netip.IPv4Unspecified(), remote[i]), + remote: netip.AddrPortFrom(remoteAddr, remote[i]), }) } return out, nil pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy