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

Commit0247c28

Browse files
committed
fix: fix parsing of IPv6 addresses in coder port-forward
1 parentb5fbfd7 commit0247c28

File tree

3 files changed

+105
-79
lines changed

3 files changed

+105
-79
lines changed

‎cli/portforward.go‎

Lines changed: 42 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,51 @@ 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+
//
339+
// Important capturing groups:
340+
//
341+
// 2: local IP address (including [] for IPv6)
342+
// 3: local port, or start of local port range
343+
// 5: end of local port range
344+
// 7: remote port, or start of remote port range
345+
// 9: end or remote port range
346+
varspecRegexp=regexp.MustCompile(`^((\[[0-9a-fA-F:]+]|\d+\.\d+\.\d+\.\d+):)?(\d+)(-(\d+))?(:(\d+)(-(\d+))?)?$`)
347+
329348
funcparseSrcDestPorts(instring) ([]parsedSrcDestPort,error) {
330349
var (
331350
errerror
332-
parts=strings.Split(in,":")
333351
localAddr=netip.AddrFrom4([4]byte{127,0,0,1})
334352
remoteAddr=netip.AddrFrom4([4]byte{127,0,0,1})
335353
)
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:
354+
groups:=specRegexp.FindStringSubmatch(in)
355+
iflen(groups)==0 {
360356
returnnil,xerrors.Errorf("invalid port specification %q",in)
361357
}
362-
363-
if!strings.Contains(parts[0],"-") {
364-
localPort,err:=parsePort(parts[0])
358+
ifgroups[2]!="" {
359+
localAddr,err=netip.ParseAddr(strings.Trim(groups[2],"[]"))
365360
iferr!=nil {
366-
returnnil,xerrors.Errorf("parse local port from %q: %w",in,err)
361+
returnnil,xerrors.Errorf("invalid IP address %q",groups[2])
367362
}
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
377363
}
378364

379-
local,err:=parsePortRange(parts[0])
365+
local,err:=parsePortRange(groups[3],groups[5])
380366
iferr!=nil {
381367
returnnil,xerrors.Errorf("parse local port range from %q: %w",in,err)
382368
}
383-
remote,err:=parsePortRange(parts[1])
384-
iferr!=nil {
385-
returnnil,xerrors.Errorf("parse remote port range from %q: %w",in,err)
369+
remote:=local
370+
ifgroups[7]!="" {
371+
remote,err=parsePortRange(groups[7],groups[9])
372+
iferr!=nil {
373+
returnnil,xerrors.Errorf("parse remote port range from %q: %w",in,err)
374+
}
386375
}
387376
iflen(local)!=len(remote) {
388377
returnnil,xerrors.Errorf("port ranges must be the same length, got %d ports forwarded to %d ports",len(local),len(remote))
@@ -397,18 +386,17 @@ func parseSrcDestPorts(in string) ([]parsedSrcDestPort, error) {
397386
returnout,nil
398387
}
399388

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])
389+
funcparsePortRange(s,estring) ([]uint16,error) {
390+
start,err:=parsePort(s)
406391
iferr!=nil {
407-
returnnil,xerrors.Errorf("parse range start port from %q: %w",in,err)
392+
returnnil,xerrors.Errorf("parse range start port from %q: %w",s,err)
408393
}
409-
end,err:=parsePort(parts[1])
410-
iferr!=nil {
411-
returnnil,xerrors.Errorf("parse range end port from %q: %w",in,err)
394+
end:=start
395+
iflen(e)!=0 {
396+
end,err=parsePort(e)
397+
iferr!=nil {
398+
returnnil,xerrors.Errorf("parse range end port from %q: %w",e,err)
399+
}
412400
}
413401
ifend<start {
414402
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