Skip to content

Commit 711b859

Browse files
committed
add support for parsing IPv4-mapped IPv6 addresses
Fixes #94
1 parent 195fedc commit 711b859

File tree

4 files changed

+53
-9
lines changed

4 files changed

+53
-9
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/pires/go-proxyproto
22

3-
go 1.13
3+
go 1.18

header_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
const (
1616
NO_PROTOCOL = "There is no spoon"
1717
IP4_ADDR = "127.0.0.1"
18+
IP4IN6_ADDR = "::ffff:127.0.0.1"
1819
IP6_ADDR = "::1"
1920
IP6_LONG_ADDR = "1234:5678:9abc:def0:cafe:babe:dead:2bad"
2021
PORT = 65533

v1.go

+18-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"bytes"
66
"fmt"
77
"net"
8+
"net/netip"
89
"strconv"
910
"strings"
1011
)
@@ -221,11 +222,22 @@ func parseV1PortNumber(portStr string) (int, error) {
221222
return port, nil
222223
}
223224

224-
func parseV1IPAddress(protocol AddressFamilyAndProtocol, addrStr string) (addr net.IP, err error) {
225-
addr = net.ParseIP(addrStr)
226-
tryV4 := addr.To4()
227-
if (protocol == TCPv4 && tryV4 == nil) || (protocol == TCPv6 && tryV4 != nil) {
228-
err = ErrInvalidAddress
225+
func parseV1IPAddress(protocol AddressFamilyAndProtocol, addrStr string) (net.IP, error) {
226+
addr, err := netip.ParseAddr(addrStr)
227+
if err != nil {
228+
return nil, ErrInvalidAddress
229229
}
230-
return
230+
231+
switch protocol {
232+
case TCPv4:
233+
if addr.Is4() {
234+
return net.IP(addr.AsSlice()), nil
235+
}
236+
case TCPv6:
237+
if addr.Is6() || addr.Is4In6() {
238+
return net.IP(addr.AsSlice()), nil
239+
}
240+
}
241+
242+
return nil, ErrInvalidAddress
231243
}

v1_test.go

+33-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ import (
1313

1414
var (
1515
IPv4AddressesAndPorts = strings.Join([]string{IP4_ADDR, IP4_ADDR, strconv.Itoa(PORT), strconv.Itoa(PORT)}, separator)
16+
IPv4In6AddressesAndPorts = strings.Join([]string{IP4IN6_ADDR, IP4IN6_ADDR, strconv.Itoa(PORT), strconv.Itoa(PORT)}, separator)
1617
IPv4AddressesAndInvalidPorts = strings.Join([]string{IP4_ADDR, IP4_ADDR, strconv.Itoa(INVALID_PORT), strconv.Itoa(INVALID_PORT)}, separator)
1718
IPv6AddressesAndPorts = strings.Join([]string{IP6_ADDR, IP6_ADDR, strconv.Itoa(PORT), strconv.Itoa(PORT)}, separator)
1819
IPv6LongAddressesAndPorts = strings.Join([]string{IP6_LONG_ADDR, IP6_LONG_ADDR, strconv.Itoa(PORT), strconv.Itoa(PORT)}, separator)
1920

20-
fixtureTCP4V1 = "PROXY TCP4 " + IPv4AddressesAndPorts + crlf + "GET /"
21-
fixtureTCP6V1 = "PROXY TCP6 " + IPv6AddressesAndPorts + crlf + "GET /"
21+
fixtureTCP4V1 = "PROXY TCP4 " + IPv4AddressesAndPorts + crlf + "GET /"
22+
fixtureTCP6V1 = "PROXY TCP6 " + IPv6AddressesAndPorts + crlf + "GET /"
23+
fixtureTCP4IN6V1 = "PROXY TCP6 " + IPv4In6AddressesAndPorts + crlf + "GET /"
2224

2325
fixtureTCP6V1Overflow = "PROXY TCP6 " + IPv6LongAddressesAndPorts
2426

@@ -66,6 +68,11 @@ var invalidParseV1Tests = []struct {
6668
reader: newBufioReader([]byte("PROXY TCP4 " + IPv4AddressesAndPorts)),
6769
expectedError: ErrCantReadVersion1Header,
6870
},
71+
{
72+
desc: "invalid IP address",
73+
reader: newBufioReader([]byte("PROXY TCP4 invalid invalid 65533 65533" + crlf)),
74+
expectedError: ErrInvalidAddress,
75+
},
6976
{
7077
desc: "TCP6 with IPv4 addresses",
7178
reader: newBufioReader([]byte("PROXY TCP6 " + IPv4AddressesAndPorts + crlf)),
@@ -76,6 +83,11 @@ var invalidParseV1Tests = []struct {
7683
reader: newBufioReader([]byte("PROXY TCP4 " + IPv6AddressesAndPorts + crlf)),
7784
expectedError: ErrInvalidAddress,
7885
},
86+
{
87+
desc: "TCP4 with IPv4 mapped addresses",
88+
reader: newBufioReader([]byte("PROXY TCP4 " + IPv4In6AddressesAndPorts + crlf)),
89+
expectedError: ErrInvalidAddress,
90+
},
7991
{
8092
desc: "TCP4 with invalid port",
8193
reader: newBufioReader([]byte("PROXY TCP4 " + IPv4AddressesAndInvalidPorts + crlf)),
@@ -102,6 +114,7 @@ var validParseAndWriteV1Tests = []struct {
102114
desc string
103115
reader *bufio.Reader
104116
expectedHeader *Header
117+
skipWrite bool
105118
}{
106119
{
107120
desc: "TCP4",
@@ -125,6 +138,21 @@ var validParseAndWriteV1Tests = []struct {
125138
DestinationAddr: v6addr,
126139
},
127140
},
141+
{
142+
desc: "TCP4IN6",
143+
reader: bufio.NewReader(strings.NewReader(fixtureTCP4IN6V1)),
144+
expectedHeader: &Header{
145+
Version: 1,
146+
Command: PROXY,
147+
TransportProtocol: TCPv6,
148+
SourceAddr: v4addr,
149+
DestinationAddr: v4addr,
150+
},
151+
// we skip write test because net.ParseIP converts ::ffff:127.0.0.1 to v4
152+
// instead of preserving the v4 in v6 form, so, after serializing the header,
153+
// we end up with v6 protocol and a v4 IP which is invalid
154+
skipWrite: true,
155+
},
128156
{
129157
desc: "unknown",
130158
reader: bufio.NewReader(strings.NewReader(fixtureUnknown)),
@@ -165,6 +193,9 @@ func TestParseV1Valid(t *testing.T) {
165193

166194
func TestWriteV1Valid(t *testing.T) {
167195
for _, tt := range validParseAndWriteV1Tests {
196+
if tt.skipWrite {
197+
continue
198+
}
168199
t.Run(tt.desc, func(t *testing.T) {
169200
var b bytes.Buffer
170201
w := bufio.NewWriter(&b)

0 commit comments

Comments
 (0)