Skip to content

Commit b6f440c

Browse files
authoredJan 20, 2021
Merge pull request #62 from bohanyang/unspec-zero-length
v2: read length and skip the bytes for UNSPEC
2 parents 22bc614 + 70665b5 commit b6f440c

File tree

2 files changed

+100
-48
lines changed

2 files changed

+100
-48
lines changed
 

‎v2.go

+63-45
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,15 @@ import (
1010
)
1111

1212
var (
13-
lengthV4 = uint16(12)
14-
lengthV6 = uint16(36)
15-
lengthUnix = uint16(216)
16-
13+
lengthUnspec = uint16(0)
14+
lengthV4 = uint16(12)
15+
lengthV6 = uint16(36)
16+
lengthUnix = uint16(216)
17+
lengthUnspecBytes = func() []byte {
18+
a := make([]byte, 2)
19+
binary.BigEndian.PutUint16(a, lengthUnspec)
20+
return a
21+
}()
1722
lengthV4Bytes = func() []byte {
1823
a := make([]byte, 2)
1924
binary.BigEndian.PutUint16(a, lengthV4)
@@ -82,13 +87,9 @@ func parseVersion2(reader *bufio.Reader) (header *Header, err error) {
8287
return nil, ErrCantReadAddressFamilyAndProtocol
8388
}
8489
header.TransportProtocol = AddressFamilyAndProtocol(b14)
85-
// UNSPEC is only supported when LOCAL is set.
86-
if header.TransportProtocol == UNSPEC {
87-
if header.Command != LOCAL {
88-
return nil, ErrUnsupportedAddressFamilyAndProtocol
89-
}
90-
// Ignore everything else.
91-
return header, nil
90+
// UNSPEC is only supported when LOCAL is set.
91+
if header.TransportProtocol == UNSPEC && header.Command != LOCAL {
92+
return nil, ErrUnsupportedAddressFamilyAndProtocol
9293
}
9394

9495
// Make sure there are bytes available as specified in length
@@ -100,46 +101,56 @@ func parseVersion2(reader *bufio.Reader) (header *Header, err error) {
100101
return nil, ErrInvalidLength
101102
}
102103

104+
// Return early if the length is zero, which means that
105+
// there's no address information and TLVs present for UNSPEC.
106+
if length == 0 {
107+
return header, nil
108+
}
109+
103110
if _, err := reader.Peek(int(length)); err != nil {
104111
return nil, ErrInvalidLength
105112
}
106113

107114
// Length-limited reader for payload section
108115
payloadReader := io.LimitReader(reader, int64(length)).(*io.LimitedReader)
109116

110-
// Read addresses and ports
111-
if header.TransportProtocol.IsIPv4() {
112-
var addr _addr4
113-
if err := binary.Read(payloadReader, binary.BigEndian, &addr); err != nil {
114-
return nil, ErrInvalidAddress
115-
}
116-
header.SourceAddr = newIPAddr(header.TransportProtocol, addr.Src[:], addr.SrcPort)
117-
header.DestinationAddr = newIPAddr(header.TransportProtocol, addr.Dst[:], addr.DstPort)
118-
} else if header.TransportProtocol.IsIPv6() {
119-
var addr _addr6
120-
if err := binary.Read(payloadReader, binary.BigEndian, &addr); err != nil {
121-
return nil, ErrInvalidAddress
122-
}
123-
header.SourceAddr = newIPAddr(header.TransportProtocol, addr.Src[:], addr.SrcPort)
124-
header.DestinationAddr = newIPAddr(header.TransportProtocol, addr.Dst[:], addr.DstPort)
125-
} else if header.TransportProtocol.IsUnix() {
126-
var addr _addrUnix
127-
if err := binary.Read(payloadReader, binary.BigEndian, &addr); err != nil {
128-
return nil, ErrInvalidAddress
129-
}
117+
// Read addresses and ports for protocols other than UNSPEC.
118+
// Ignore address information for UNSPEC, and skip straight to read TLVs,
119+
// since the length is greater than zero.
120+
if header.TransportProtocol != UNSPEC {
121+
if header.TransportProtocol.IsIPv4() {
122+
var addr _addr4
123+
if err := binary.Read(payloadReader, binary.BigEndian, &addr); err != nil {
124+
return nil, ErrInvalidAddress
125+
}
126+
header.SourceAddr = newIPAddr(header.TransportProtocol, addr.Src[:], addr.SrcPort)
127+
header.DestinationAddr = newIPAddr(header.TransportProtocol, addr.Dst[:], addr.DstPort)
128+
} else if header.TransportProtocol.IsIPv6() {
129+
var addr _addr6
130+
if err := binary.Read(payloadReader, binary.BigEndian, &addr); err != nil {
131+
return nil, ErrInvalidAddress
132+
}
133+
header.SourceAddr = newIPAddr(header.TransportProtocol, addr.Src[:], addr.SrcPort)
134+
header.DestinationAddr = newIPAddr(header.TransportProtocol, addr.Dst[:], addr.DstPort)
135+
} else if header.TransportProtocol.IsUnix() {
136+
var addr _addrUnix
137+
if err := binary.Read(payloadReader, binary.BigEndian, &addr); err != nil {
138+
return nil, ErrInvalidAddress
139+
}
130140

131-
network := "unix"
132-
if header.TransportProtocol.IsDatagram() {
133-
network = "unixgram"
134-
}
141+
network := "unix"
142+
if header.TransportProtocol.IsDatagram() {
143+
network = "unixgram"
144+
}
135145

136-
header.SourceAddr = &net.UnixAddr{
137-
Net: network,
138-
Name: parseUnixName(addr.Src[:]),
139-
}
140-
header.DestinationAddr = &net.UnixAddr{
141-
Net: network,
142-
Name: parseUnixName(addr.Dst[:]),
146+
header.SourceAddr = &net.UnixAddr{
147+
Net: network,
148+
Name: parseUnixName(addr.Src[:]),
149+
}
150+
header.DestinationAddr = &net.UnixAddr{
151+
Net: network,
152+
Name: parseUnixName(addr.Dst[:]),
153+
}
143154
}
144155
}
145156

@@ -157,9 +168,14 @@ func (header *Header) formatVersion2() ([]byte, error) {
157168
buf.Write(SIGV2)
158169
buf.WriteByte(header.Command.toByte())
159170
buf.WriteByte(header.TransportProtocol.toByte())
160-
// When UNSPEC, the receiver must ignore addresses and ports.
161-
// Therefore there's no point in writing it.
162-
if !header.TransportProtocol.IsUnspec() {
171+
if header.TransportProtocol.IsUnspec() {
172+
// For UNSPEC, write no addresses and ports but only TLVs if they are present
173+
hdrLen, err := addTLVLen(lengthUnspecBytes, len(header.rawTLVs))
174+
if err != nil {
175+
return nil, err
176+
}
177+
buf.Write(hdrLen)
178+
} else {
163179
var addrSrc, addrDst []byte
164180
if header.TransportProtocol.IsIPv4() {
165181
hdrLen, err := addTLVLen(lengthV4Bytes, len(header.rawTLVs))
@@ -221,6 +237,8 @@ func (header *Header) validateLength(length uint16) bool {
221237
return length >= lengthV6
222238
} else if header.TransportProtocol.IsUnix() {
223239
return length >= lengthUnix
240+
} else if header.TransportProtocol.IsUnspec() {
241+
return length >= lengthUnspec
224242
}
225243
return false
226244
}

‎v2_test.go

+37-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ var (
5656
}()
5757
fixtureIPv4V2TLV = fixtureWithTLV(lengthV4Bytes, fixtureIPv4Address, fixtureTLV)
5858
fixtureIPv6V2TLV = fixtureWithTLV(lengthV6Bytes, fixtureIPv6Address, fixtureTLV)
59+
fixtureUnspecTLV = fixtureWithTLV(lengthUnspecBytes, []byte{}, fixtureTLV)
5960

6061
// Arbitrary bytes following proxy bytes
6162
arbitraryTailBytes = []byte{'\x99', '\x97', '\x98'}
@@ -116,6 +117,11 @@ var invalidParseV2Tests = []struct {
116117
reader: newBufioReader(append(SIGV2, byte(PROXY), byte(TCPv4), invalidRune)),
117118
expectedError: ErrCantReadLength,
118119
},
120+
{
121+
desc: "unspec but no length",
122+
reader: newBufioReader(append(SIGV2, byte(LOCAL), byte(UNSPEC))),
123+
expectedError: ErrCantReadLength,
124+
},
119125
{
120126
desc: "TCPv4 with mismatching length",
121127
reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(TCPv4)), lengthV4Bytes...)),
@@ -132,10 +138,15 @@ var invalidParseV2Tests = []struct {
132138
expectedError: ErrInvalidLength,
133139
},
134140
{
135-
desc: "TCPv4 length zero but with address and ports",
141+
desc: "TCPv6 with IPv6 length but IPv4 address and ports",
136142
reader: newBufioReader(append(append(append(SIGV2, byte(PROXY), byte(TCPv6)), lengthV6Bytes...), fixtureIPv4Address...)),
137143
expectedError: ErrInvalidLength,
138144
},
145+
{
146+
desc: "unspec length greater than zero but no TLVs",
147+
reader: newBufioReader(append(append(SIGV2, byte(LOCAL), byte(UNSPEC)), fixtureUnspecTLV[:2]...)),
148+
expectedError: ErrInvalidLength,
149+
},
139150
}
140151

141152
func TestParseV2Invalid(t *testing.T) {
@@ -166,7 +177,7 @@ var validParseAndWriteV2Tests = []struct {
166177
},
167178
{
168179
desc: "local unspec",
169-
reader: newBufioReader(append(append(SIGV2, byte(LOCAL), byte(TCPv4)), fixtureIPv4V2...)),
180+
reader: newBufioReader(append(append(SIGV2, byte(LOCAL), byte(UNSPEC)), lengthUnspecBytes...)),
170181
expectedHeader: &Header{
171182
Version: 2,
172183
Command: LOCAL,
@@ -221,6 +232,18 @@ var validParseAndWriteV2Tests = []struct {
221232
rawTLVs: fixtureTLV,
222233
},
223234
},
235+
{
236+
desc: "local unspec with TLV",
237+
reader: newBufioReader(append(append(SIGV2, byte(LOCAL), byte(UNSPEC)), fixtureUnspecTLV...)),
238+
expectedHeader: &Header{
239+
Version: 2,
240+
Command: LOCAL,
241+
TransportProtocol: UNSPEC,
242+
SourceAddr: nil,
243+
DestinationAddr: nil,
244+
rawTLVs: fixtureTLV,
245+
},
246+
},
224247
{
225248
desc: "proxy UDPv4",
226249
reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(UDPv4)), fixtureIPv4V2...)),
@@ -255,7 +278,7 @@ var validParseAndWriteV2Tests = []struct {
255278
},
256279
},
257280
{
258-
desc: "proxy unix datagram ",
281+
desc: "proxy unix datagram",
259282
reader: newBufioReader(append(append(SIGV2, byte(PROXY), byte(UnixDatagram)), fixtureUnixV2...)),
260283
expectedHeader: &Header{
261284
Version: 2,
@@ -460,6 +483,17 @@ var tlvFormatTests = []struct {
460483
rawTLVs: make([]byte, 1<<16),
461484
},
462485
},
486+
{
487+
desc: "local unspec",
488+
header: &Header{
489+
Version: 2,
490+
Command: LOCAL,
491+
TransportProtocol: UNSPEC,
492+
SourceAddr: nil,
493+
DestinationAddr: nil,
494+
rawTLVs: make([]byte, 1<<16),
495+
},
496+
},
463497
}
464498

465499
func TestV2TLVFormatTooLargeTLV(t *testing.T) {

0 commit comments

Comments
 (0)
Please sign in to comment.