Skip to content

Commit 3db7f7b

Browse files
authored
fix: handle bare IPv6 addresses in proxy protocol header (fixes minekube#670) (minekube#673)
When a client connects via IPv6 through Connect, the address string (e.g. "2a09:bac6:d73f:28::4:31d") has no brackets or port. net.SplitHostPort returns "too many colons in address" for this format, which was unhandled, causing splitHostPort to return an empty host and triggering a panic in protoutil.convert.
1 parent 1c5d6c8 commit 3db7f7b

3 files changed

Lines changed: 55 additions & 15 deletions

File tree

pkg/edition/java/internal/protoutil/util_test.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,29 @@ func TestProxyHeader(t *testing.T) {
2222
Port: 25566,
2323
}
2424

25+
// Bare IPv6 addresses without brackets and port (as reported in issue #670)
26+
bareIPv6Src := connect.Addr("2a09:bac6:d73f:28::4:31d")
27+
bareIPv6Src2 := connect.Addr("2a09:bac6:d73f:3046::4cf:74")
28+
2529
testCases := []struct {
26-
name string
27-
srcAddr net.Addr
28-
destAddr net.Addr
30+
name string
31+
srcAddr net.Addr
32+
destAddr net.Addr
33+
skipStrCompare bool // bare IPv6 addr strings differ from net.TCPAddr strings
2934
}{
30-
{"virtual addr should not fail to write proxy header", srcAddr, destAddr},
31-
{"mix of v4 and v6 should not fail to write proxy header", v4Addr, v6Addr},
32-
{"mix of v6 and v4 should not fail to write proxy header", v6Addr, v4Addr},
33-
{"v4 addr should not fail to write proxy header", v4Addr, v4Addr},
34-
{"v6 addr should not fail to write proxy header", v6Addr, v6Addr},
35-
{"mix of v4 and virtual should not fail to write proxy header", v4Addr, destAddr},
36-
{"mix of v6 and virtual should not fail to write proxy header", v6Addr, destAddr},
37-
{"mix of virtual and v4 should not fail to write proxy header", srcAddr, v4Addr},
38-
{"mix of virtual and v6 should not fail to write proxy header", srcAddr, v6Addr},
35+
{"virtual addr should not fail to write proxy header", srcAddr, destAddr, false},
36+
{"mix of v4 and v6 should not fail to write proxy header", v4Addr, v6Addr, false},
37+
{"mix of v6 and v4 should not fail to write proxy header", v6Addr, v4Addr, false},
38+
{"v4 addr should not fail to write proxy header", v4Addr, v4Addr, false},
39+
{"v6 addr should not fail to write proxy header", v6Addr, v6Addr, false},
40+
{"mix of v4 and virtual should not fail to write proxy header", v4Addr, destAddr, false},
41+
{"mix of v6 and virtual should not fail to write proxy header", v6Addr, destAddr, false},
42+
{"mix of virtual and v4 should not fail to write proxy header", srcAddr, v4Addr, false},
43+
{"mix of virtual and v6 should not fail to write proxy header", srcAddr, v6Addr, false},
44+
{"bare IPv6 src should not panic", bareIPv6Src, destAddr, true},
45+
{"bare IPv6 src2 should not panic", bareIPv6Src2, destAddr, true},
46+
{"bare IPv6 src with v4 dest should not panic", bareIPv6Src, v4Addr, true},
47+
{"bare IPv6 src with v6 dest should not panic", bareIPv6Src, v6Addr, true},
3948
}
4049

4150
for _, tc := range testCases {
@@ -44,8 +53,10 @@ func TestProxyHeader(t *testing.T) {
4453
require.NotNil(t, header)
4554
require.NotNil(t, header.SourceAddr)
4655
require.NotNil(t, header.DestinationAddr)
47-
require.Equal(t, tc.srcAddr.String(), header.SourceAddr.String())
48-
require.Equal(t, tc.destAddr.String(), header.DestinationAddr.String())
56+
if !tc.skipStrCompare {
57+
require.Equal(t, tc.srcAddr.String(), header.SourceAddr.String())
58+
require.Equal(t, tc.destAddr.String(), header.DestinationAddr.String())
59+
}
4960

5061
// Create a buffer to write the header
5162
buf := new(bytes.Buffer)

pkg/util/netutil/util.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func splitHostPort(addr string) (host string, port uint16, err error) {
5656
host, portStr, err = net.SplitHostPort(addr)
5757
if err == nil {
5858
portInt, err = strconv.Atoi(portStr)
59-
} else if isMissingPortErr(err) {
59+
} else if isMissingPortErr(err) || isTooManyColonsErr(err) {
6060
host = addr
6161
err = nil
6262
}
@@ -74,3 +74,8 @@ func isMissingPortErr(err error) bool {
7474
var addrErr *net.AddrError
7575
return err != nil && errors.As(err, &addrErr) && addrErr.Err == "missing port in address"
7676
}
77+
78+
func isTooManyColonsErr(err error) bool {
79+
var addrErr *net.AddrError
80+
return err != nil && errors.As(err, &addrErr) && addrErr.Err == "too many colons in address"
81+
}

pkg/util/netutil/util_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,27 @@ func TestSplitHostPort_isMissingPortErr(t *testing.T) {
2828
_, _, err := net.SplitHostPort("host-without-port")
2929
require.True(t, isMissingPortErr(err))
3030
}
31+
32+
func TestHostPort_BareIPv6(t *testing.T) {
33+
// Bare IPv6 addresses without brackets and port (e.g. from connect.Addr)
34+
// should return the full address as host with port 0.
35+
tests := []struct {
36+
addr string
37+
host string
38+
port uint16
39+
}{
40+
{"2a09:bac6:d73f:28::4:31d", "2a09:bac6:d73f:28::4:31d", 0},
41+
{"2a09:bac6:d73f:3046::4cf:74", "2a09:bac6:d73f:3046::4cf:74", 0},
42+
{"::1", "::1", 0},
43+
{"[::1]:25565", "::1", 25565},
44+
{"127.0.0.1:25565", "127.0.0.1", 25565},
45+
}
46+
for _, tc := range tests {
47+
t.Run(tc.addr, func(t *testing.T) {
48+
addr := &address{addr: tc.addr}
49+
host, port := HostPort(addr)
50+
require.Equal(t, tc.host, host)
51+
require.Equal(t, tc.port, port)
52+
})
53+
}
54+
}

0 commit comments

Comments
 (0)