Skip to content

Commit

Permalink
fix: proxyproto: invalid address
Browse files Browse the repository at this point in the history
  • Loading branch information
robinbraemer committed Jan 30, 2024
1 parent b201e6b commit 4030e57
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 9 deletions.
6 changes: 3 additions & 3 deletions .examples/extend/simple-proxy/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ require (
github.com/go-logr/zapr v1.3.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jellydator/ttlcache/v3 v3.1.1 // indirect
github.com/knadh/koanf/providers/file v0.1.0 // indirect
Expand All @@ -35,7 +35,7 @@ require (
github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pires/go-proxyproto v0.7.0 // indirect
github.com/pires/go-proxyproto v0.7.1-0.20231012122632-e5b291b295b4 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
Expand All @@ -58,7 +58,7 @@ require (
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect
google.golang.org/grpc v1.60.1 // indirect
google.golang.org/grpc v1.61.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
3 changes: 3 additions & 0 deletions .examples/extend/simple-proxy/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
Expand Down Expand Up @@ -122,6 +123,7 @@ github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOS
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
github.com/pires/go-proxyproto v0.7.1-0.20231012122632-e5b291b295b4/go.mod h1:hm9CitpinLa2As6mIQh1AzhxHULm1BCYGUTbNcO6f2Q=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
Expand Down Expand Up @@ -294,6 +296,7 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/jellydator/ttlcache/v3 v3.1.1
github.com/knadh/koanf/providers/file v0.1.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/pires/go-proxyproto v0.7.0
github.com/pires/go-proxyproto v0.7.1-0.20231012122632-e5b291b295b4
github.com/robinbraemer/event v0.0.1
github.com/rs/xid v1.5.0
github.com/sandertv/go-raknet v1.12.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOS
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
github.com/pires/go-proxyproto v0.7.1-0.20231012122632-e5b291b295b4 h1:VM7Tse0I0kTEaO/Rk7BPjmDqfiUcpv+RWtiwIY04pgI=
github.com/pires/go-proxyproto v0.7.1-0.20231012122632-e5b291b295b4/go.mod h1:hm9CitpinLa2As6mIQh1AzhxHULm1BCYGUTbNcO6f2Q=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
Expand Down
56 changes: 51 additions & 5 deletions pkg/edition/java/internal/protoutil/util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package protoutil

import (
"fmt"
"go.minekube.com/gate/pkg/util/netutil"
"net"

"github.com/pires/go-proxyproto"
Expand All @@ -19,10 +21,54 @@ func Protocol(subject any) (proto.Protocol, bool) {

// ProxyHeader returns a proxy header for the given address.
func ProxyHeader(srcAddr, destAddr net.Addr) *proxyproto.Header {
// Passing destination address as srcAddr fixes disconnect error
// where the backend only allows IPv6 but the client connected with IPv4 (or vice-versa).
// This assumes that the srcAddr uses the same protocol (e.g. TCP) as the destAddr.
header := proxyproto.HeaderProxyFromAddrs(0, destAddr, destAddr)
header.SourceAddr = srcAddr
srcAddr = convert(srcAddr)
destAddr = convert(destAddr)

header := proxyproto.HeaderProxyFromAddrs(0, srcAddr, destAddr)

mismatch := func(srcIP, destIP net.IP) bool {
// on mismatch v4 to v6: use v6
return len(srcIP.To4()) == net.IPv4len && len(destIP) == net.IPv6len
}

switch sourceAddr := header.SourceAddr.(type) {
case *net.TCPAddr:
dstAddr, ok := destAddr.(*net.TCPAddr)
if ok && mismatch(sourceAddr.IP, dstAddr.IP) {
header.TransportProtocol = proxyproto.TCPv6
sourceAddr.IP = sourceAddr.IP.To16()
header.SourceAddr = sourceAddr
}
case *net.UDPAddr:
dstAddr, ok := header.DestinationAddr.(*net.UDPAddr)
if ok && mismatch(sourceAddr.IP, dstAddr.IP) {
header.TransportProtocol = proxyproto.UDPv6
sourceAddr.IP = sourceAddr.IP.To16()
header.SourceAddr = sourceAddr
}
}
return header
}

func convert(addr net.Addr) net.Addr {
if addr == nil {
return nil
}
switch addr.(type) {
case *net.UDPAddr, *net.UnixAddr, *net.IPAddr, *net.TCPAddr:
// fast path
return addr
default:
// slow path
host, port := netutil.HostPort(addr)
ip := net.ParseIP(host)
if ip == nil {
err := fmt.Errorf("invalid IP address %T: %+v (host: %s, port: %d)", addr, addr, host, port)
panic(err)
}
return &net.TCPAddr{
IP: ip,
Port: int(port),
}
}
}
55 changes: 55 additions & 0 deletions pkg/edition/java/internal/protoutil/util_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package protoutil

import (
"bytes"
"github.com/stretchr/testify/require"
"go.minekube.com/connect"
"net"
"testing"
)

func TestProxyHeader(t *testing.T) {
srcAddr := connect.Addr("104.28.243.188:0")
destAddr := connect.Addr("127.0.0.1:25565")

v4Addr := &net.TCPAddr{
IP: net.IPv4(127, 0, 0, 1),
Port: 25565,
}
v6Addr := &net.TCPAddr{
IP: net.IPv6loopback,
Port: 25566,
}

testCases := []struct {
name string
srcAddr net.Addr
destAddr net.Addr
}{
{"virtual addr should not fail to write proxy header", srcAddr, destAddr},
{"mix of v4 and v6 should not fail to write proxy header", v4Addr, v6Addr},
{"mix of v6 and v4 should not fail to write proxy header", v6Addr, v4Addr},
{"v4 addr should not fail to write proxy header", v4Addr, v4Addr},
{"v6 addr should not fail to write proxy header", v6Addr, v6Addr},
{"mix of v4 and virtual should not fail to write proxy header", v4Addr, destAddr},
{"mix of v6 and virtual should not fail to write proxy header", v6Addr, destAddr},
{"mix of virtual and v4 should not fail to write proxy header", srcAddr, v4Addr},
{"mix of virtual and v6 should not fail to write proxy header", srcAddr, v6Addr},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
header := ProxyHeader(tc.srcAddr, tc.destAddr)
require.NotNil(t, header)
require.NotNil(t, header.SourceAddr)
require.NotNil(t, header.DestinationAddr)
require.Equal(t, tc.srcAddr.String(), header.SourceAddr.String())
require.Equal(t, tc.destAddr.String(), header.DestinationAddr.String())

// Create a buffer to write the header
buf := new(bytes.Buffer)
_, err := header.WriteTo(buf)
require.NoError(t, err)
})
}
}

0 comments on commit 4030e57

Please sign in to comment.