Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit648cdd0

Browse files
authored
fix: fix parsing of IPv6 addresses in coder port-forward (#15627)
fixes:#15561Fixes parsing of IPv6 local addresses on `coder port-forward`
1 parenta8becfb commit648cdd0

File tree

3 files changed

+107
-79
lines changed

3 files changed

+107
-79
lines changed

‎cli/portforward.go

Lines changed: 44 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/netip"
88
"os"
99
"os/signal"
10+
"regexp"
1011
"strconv"
1112
"strings"
1213
"sync"
@@ -263,7 +264,7 @@ func parsePortForwards(tcpSpecs, udpSpecs []string) ([]portForwardSpec, error) {
263264

264265
for_,specEntry:=rangetcpSpecs {
265266
for_,spec:=rangestrings.Split(specEntry,",") {
266-
ports,err:=parseSrcDestPorts(spec)
267+
ports,err:=parseSrcDestPorts(strings.TrimSpace(spec))
267268
iferr!=nil {
268269
returnnil,xerrors.Errorf("failed to parse TCP port-forward specification %q: %w",spec,err)
269270
}
@@ -281,7 +282,7 @@ func parsePortForwards(tcpSpecs, udpSpecs []string) ([]portForwardSpec, error) {
281282

282283
for_,specEntry:=rangeudpSpecs {
283284
for_,spec:=rangestrings.Split(specEntry,",") {
284-
ports,err:=parseSrcDestPorts(spec)
285+
ports,err:=parseSrcDestPorts(strings.TrimSpace(spec))
285286
iferr!=nil {
286287
returnnil,xerrors.Errorf("failed to parse UDP port-forward specification %q: %w",spec,err)
287288
}
@@ -326,63 +327,53 @@ type parsedSrcDestPort struct {
326327
local,remote netip.AddrPort
327328
}
328329

330+
// specRegexp matches port specs. It handles all the following formats:
331+
//
332+
// 8000
333+
// 8888:9999
334+
// 1-5:6-10
335+
// 8000-8005
336+
// 127.0.0.1:4000:4000
337+
// [::1]:8080:8081
338+
// 127.0.0.1:4000-4005
339+
// [::1]:4000-4001:5000-5001
340+
//
341+
// Important capturing groups:
342+
//
343+
// 2: local IP address (including [] for IPv6)
344+
// 3: local port, or start of local port range
345+
// 5: end of local port range
346+
// 7: remote port, or start of remote port range
347+
// 9: end or remote port range
348+
varspecRegexp=regexp.MustCompile(`^((\[[0-9a-fA-F:]+]|\d+\.\d+\.\d+\.\d+):)?(\d+)(-(\d+))?(:(\d+)(-(\d+))?)?$`)
349+
329350
funcparseSrcDestPorts(instring) ([]parsedSrcDestPort,error) {
330351
var (
331352
errerror
332-
parts=strings.Split(in,":")
333353
localAddr=netip.AddrFrom4([4]byte{127,0,0,1})
334354
remoteAddr=netip.AddrFrom4([4]byte{127,0,0,1})
335355
)
336-
337-
switchlen(parts) {
338-
case1:
339-
// Duplicate the single part
340-
parts=append(parts,parts[0])
341-
case2:
342-
// Check to see if the first part is an IP address.
343-
_localAddr,err:=netip.ParseAddr(parts[0])
344-
iferr!=nil {
345-
break
346-
}
347-
// The first part is the local address, so duplicate the port.
348-
localAddr=_localAddr
349-
parts= []string{parts[1],parts[1]}
350-
351-
case3:
352-
_localAddr,err:=netip.ParseAddr(parts[0])
353-
iferr!=nil {
354-
returnnil,xerrors.Errorf("invalid port specification %q; invalid ip %q: %w",in,parts[0],err)
355-
}
356-
localAddr=_localAddr
357-
parts=parts[1:]
358-
359-
default:
356+
groups:=specRegexp.FindStringSubmatch(in)
357+
iflen(groups)==0 {
360358
returnnil,xerrors.Errorf("invalid port specification %q",in)
361359
}
362-
363-
if!strings.Contains(parts[0],"-") {
364-
localPort,err:=parsePort(parts[0])
360+
ifgroups[2]!="" {
361+
localAddr,err=netip.ParseAddr(strings.Trim(groups[2],"[]"))
365362
iferr!=nil {
366-
returnnil,xerrors.Errorf("parse local port from %q: %w",in,err)
363+
returnnil,xerrors.Errorf("invalid IP address %q",groups[2])
367364
}
368-
remotePort,err:=parsePort(parts[1])
369-
iferr!=nil {
370-
returnnil,xerrors.Errorf("parse remote port from %q: %w",in,err)
371-
}
372-
373-
return []parsedSrcDestPort{{
374-
local:netip.AddrPortFrom(localAddr,localPort),
375-
remote:netip.AddrPortFrom(remoteAddr,remotePort),
376-
}},nil
377365
}
378366

379-
local,err:=parsePortRange(parts[0])
367+
local,err:=parsePortRange(groups[3],groups[5])
380368
iferr!=nil {
381369
returnnil,xerrors.Errorf("parse local port range from %q: %w",in,err)
382370
}
383-
remote,err:=parsePortRange(parts[1])
384-
iferr!=nil {
385-
returnnil,xerrors.Errorf("parse remote port range from %q: %w",in,err)
371+
remote:=local
372+
ifgroups[7]!="" {
373+
remote,err=parsePortRange(groups[7],groups[9])
374+
iferr!=nil {
375+
returnnil,xerrors.Errorf("parse remote port range from %q: %w",in,err)
376+
}
386377
}
387378
iflen(local)!=len(remote) {
388379
returnnil,xerrors.Errorf("port ranges must be the same length, got %d ports forwarded to %d ports",len(local),len(remote))
@@ -397,18 +388,17 @@ func parseSrcDestPorts(in string) ([]parsedSrcDestPort, error) {
397388
returnout,nil
398389
}
399390

400-
funcparsePortRange(instring) ([]uint16,error) {
401-
parts:=strings.Split(in,"-")
402-
iflen(parts)!=2 {
403-
returnnil,xerrors.Errorf("invalid port range specification %q",in)
404-
}
405-
start,err:=parsePort(parts[0])
391+
funcparsePortRange(s,estring) ([]uint16,error) {
392+
start,err:=parsePort(s)
406393
iferr!=nil {
407-
returnnil,xerrors.Errorf("parse range start port from %q: %w",in,err)
394+
returnnil,xerrors.Errorf("parse range start port from %q: %w",s,err)
408395
}
409-
end,err:=parsePort(parts[1])
410-
iferr!=nil {
411-
returnnil,xerrors.Errorf("parse range end port from %q: %w",in,err)
396+
end:=start
397+
iflen(e)!=0 {
398+
end,err=parsePort(e)
399+
iferr!=nil {
400+
returnnil,xerrors.Errorf("parse range end port from %q: %w",e,err)
401+
}
412402
}
413403
ifend<start {
414404
returnnil,xerrors.Errorf("range end port %v is less than start port %v",end,start)

‎cli/portforward_internal_test.go

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package cli
22

33
import (
4-
"fmt"
5-
"strings"
64
"testing"
75

86
"github.com/stretchr/testify/require"
@@ -11,21 +9,14 @@ import (
119
funcTest_parsePortForwards(t*testing.T) {
1210
t.Parallel()
1311

14-
portForwardSpecToString:=func(v []portForwardSpec) (out []string) {
15-
for_,p:=rangev {
16-
require.Equal(t,p.listenNetwork,p.dialNetwork)
17-
out=append(out,fmt.Sprintf("%s:%s",strings.Replace(p.listenAddress,"127.0.0.1:","",1),strings.Replace(p.dialAddress,"127.0.0.1:","",1)))
18-
}
19-
returnout
20-
}
2112
typeargsstruct {
2213
tcpSpecs []string
2314
udpSpecs []string
2415
}
2516
tests:= []struct {
2617
namestring
2718
argsargs
28-
want []string
19+
want []portForwardSpec
2920
wantErrbool
3021
}{
3122
{
@@ -34,28 +25,66 @@ func Test_parsePortForwards(t *testing.T) {
3425
tcpSpecs: []string{
3526
"8000,8080:8081,9000-9002,9003-9004:9005-9006",
3627
"10000",
28+
"4444-4444",
3729
},
3830
},
39-
want: []string{
40-
"8000:8000",
41-
"8080:8081",
42-
"9000:9000",
43-
"9001:9001",
44-
"9002:9002",
45-
"9003:9005",
46-
"9004:9006",
47-
"10000:10000",
31+
want: []portForwardSpec{
32+
{"tcp","127.0.0.1:8000","tcp","127.0.0.1:8000"},
33+
{"tcp","127.0.0.1:8080","tcp","127.0.0.1:8081"},
34+
{"tcp","127.0.0.1:9000","tcp","127.0.0.1:9000"},
35+
{"tcp","127.0.0.1:9001","tcp","127.0.0.1:9001"},
36+
{"tcp","127.0.0.1:9002","tcp","127.0.0.1:9002"},
37+
{"tcp","127.0.0.1:9003","tcp","127.0.0.1:9005"},
38+
{"tcp","127.0.0.1:9004","tcp","127.0.0.1:9006"},
39+
{"tcp","127.0.0.1:10000","tcp","127.0.0.1:10000"},
40+
{"tcp","127.0.0.1:4444","tcp","127.0.0.1:4444"},
41+
},
42+
},
43+
{
44+
name:"TCP IPv4 local",
45+
args:args{
46+
tcpSpecs: []string{"127.0.0.1:8080:8081"},
47+
},
48+
want: []portForwardSpec{
49+
{"tcp","127.0.0.1:8080","tcp","127.0.0.1:8081"},
50+
},
51+
},
52+
{
53+
name:"TCP IPv6 local",
54+
args:args{
55+
tcpSpecs: []string{"[::1]:8080:8081"},
56+
},
57+
want: []portForwardSpec{
58+
{"tcp","[::1]:8080","tcp","127.0.0.1:8081"},
4859
},
4960
},
5061
{
5162
name:"UDP with port range",
5263
args:args{
5364
udpSpecs: []string{"8000,8080-8081"},
5465
},
55-
want: []string{
56-
"8000:8000",
57-
"8080:8080",
58-
"8081:8081",
66+
want: []portForwardSpec{
67+
{"udp","127.0.0.1:8000","udp","127.0.0.1:8000"},
68+
{"udp","127.0.0.1:8080","udp","127.0.0.1:8080"},
69+
{"udp","127.0.0.1:8081","udp","127.0.0.1:8081"},
70+
},
71+
},
72+
{
73+
name:"UDP IPv4 local",
74+
args:args{
75+
udpSpecs: []string{"127.0.0.1:8080:8081"},
76+
},
77+
want: []portForwardSpec{
78+
{"udp","127.0.0.1:8080","udp","127.0.0.1:8081"},
79+
},
80+
},
81+
{
82+
name:"UDP IPv6 local",
83+
args:args{
84+
udpSpecs: []string{"[::1]:8080:8081"},
85+
},
86+
want: []portForwardSpec{
87+
{"udp","[::1]:8080","udp","127.0.0.1:8081"},
5988
},
6089
},
6190
{
@@ -83,8 +112,7 @@ func Test_parsePortForwards(t *testing.T) {
83112
t.Fatalf("parsePortForwards() error = %v, wantErr %v",err,tt.wantErr)
84113
return
85114
}
86-
gotStrings:=portForwardSpecToString(got)
87-
require.Equal(t,tt.want,gotStrings)
115+
require.Equal(t,tt.want,got)
88116
})
89117
}
90118
}

‎cli/portforward_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ func TestPortForward(t *testing.T) {
9292
},
9393
localAddress: []string{"10.10.10.99:9999","10.10.10.10:1010"},
9494
},
95+
{
96+
name:"TCP-IPv6",
97+
network:"tcp",flag: []string{"--tcp=[fe80::99]:9999:%v","--tcp=[fe80::10]:1010:%v"},
98+
setupRemote:func(t*testing.T) net.Listener {
99+
l,err:=net.Listen("tcp","127.0.0.1:0")
100+
require.NoError(t,err,"create TCP listener")
101+
returnl
102+
},
103+
localAddress: []string{"[fe80::99]:9999","[fe80::10]:1010"},
104+
},
95105
}
96106

97107
// Setup agent once to be shared between test-cases (avoid expensive

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp