Skip to content

Commit 10d5fbd

Browse files
authored
Merge pull request #81 from igor-kupczynski/gcp-tlv-parser
Add support for GCP extensions
2 parents 3aa7ea9 + 9f25ec7 commit 10d5fbd

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

tlvparse/gcp.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package tlvparse
2+
3+
import (
4+
"encoding/binary"
5+
6+
"github.com/pires/go-proxyproto"
7+
)
8+
9+
const (
10+
// PP2_TYPE_GCP indicates a Google Cloud Platform header
11+
PP2_TYPE_GCP proxyproto.PP2Type = 0xE0
12+
)
13+
14+
// ExtractPSCConnectionID returns the first PSC Connection ID in the TLV if it exists and is well-formed and
15+
// a bool indicating one was found.
16+
func ExtractPSCConnectionID(tlvs []proxyproto.TLV) (uint64, bool) {
17+
for _, tlv := range tlvs {
18+
if linkID, err := pscConnectionID(tlv); err == nil {
19+
return linkID, true
20+
}
21+
}
22+
return 0, false
23+
}
24+
25+
// pscConnectionID returns the ID of a GCP PSC extension TLV or errors with ErrIncompatibleTLV or
26+
// ErrMalformedTLV if it's the wrong TLV type or is malformed.
27+
//
28+
// Field Length (bytes) Description
29+
// Type 1 PP2_TYPE_GCP (0xE0)
30+
// Length 2 Length of value (always 0x0008)
31+
// Value 8 The 8-byte PSC Connection ID (decode to uint64; big endian)
32+
//
33+
// For example proxyproto.TLV{Type:0xea, Length:8, Value:[]byte{0xff, 0xff, 0xff, 0xff, 0xc0, 0xa8, 0x64, 0x02}}
34+
// will be decoded as 18446744072646845442.
35+
//
36+
// See https://cloud.google.com/vpc/docs/configure-private-service-connect-producer
37+
func pscConnectionID(t proxyproto.TLV) (uint64, error) {
38+
if !isPSCConnectionID(t) {
39+
return 0, proxyproto.ErrIncompatibleTLV
40+
}
41+
linkID := binary.BigEndian.Uint64(t.Value)
42+
return linkID, nil
43+
}
44+
45+
func isPSCConnectionID(t proxyproto.TLV) bool {
46+
return t.Type == PP2_TYPE_GCP && len(t.Value) == 8
47+
}

tlvparse/gcp_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package tlvparse
2+
3+
import (
4+
"testing"
5+
6+
"github.com/pires/go-proxyproto"
7+
)
8+
9+
func TestExtractPSCConnectionID(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
tlvs []proxyproto.TLV
13+
wantPSCConnectionID uint64
14+
wantFound bool
15+
}{
16+
{
17+
name: "nil TLVs",
18+
tlvs: nil,
19+
wantFound: false,
20+
},
21+
{
22+
name: "empty TLVs",
23+
tlvs: []proxyproto.TLV{},
24+
wantFound: false,
25+
},
26+
{
27+
name: "AWS VPC endpoint ID",
28+
tlvs: []proxyproto.TLV{
29+
{
30+
Type: 0xEA,
31+
Value: []byte{0x01, 0x76, 0x70, 0x63, 0x65, 0x2d, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33},
32+
},
33+
},
34+
wantFound: false,
35+
},
36+
{
37+
name: "GCP link ID",
38+
tlvs: []proxyproto.TLV{
39+
{
40+
Type: PP2_TYPE_GCP,
41+
Value: []byte{'\xff', '\xff', '\xff', '\xff', '\xc0', '\xa8', '\x64', '\x02'},
42+
},
43+
},
44+
wantPSCConnectionID: 18446744072646845442,
45+
wantFound: true,
46+
},
47+
{
48+
name: "Multiple TLVs",
49+
tlvs: []proxyproto.TLV{
50+
{ // AWS
51+
Type: 0xEA,
52+
Value: []byte{0x01, 0x76, 0x70, 0x63, 0x65, 0x2d, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33},
53+
},
54+
{ // Azure
55+
Type: 0xEE,
56+
Value: []byte{0x02, 0x01, 0x01, 0x01, 0x01},
57+
},
58+
{ // GCP but wrong length
59+
Type: 0xE0,
60+
Value: []byte{0xff, 0xff, 0xff},
61+
},
62+
{ // Correct
63+
Type: 0xE0,
64+
Value: []byte{'\xff', '\xff', '\xff', '\xff', '\xc0', '\xa8', '\x64', '\x02'},
65+
},
66+
},
67+
wantPSCConnectionID: 18446744072646845442,
68+
wantFound: true,
69+
},
70+
}
71+
for _, tt := range tests {
72+
t.Run(tt.name, func(t *testing.T) {
73+
linkID, hasLinkID := ExtractPSCConnectionID(tt.tlvs)
74+
if hasLinkID != tt.wantFound {
75+
t.Errorf("ExtractPSCConnectionID() got1 = %v, want %v", hasLinkID, tt.wantFound)
76+
}
77+
if linkID != tt.wantPSCConnectionID {
78+
t.Errorf("ExtractPSCConnectionID() got = %v, want %v", linkID, tt.wantPSCConnectionID)
79+
}
80+
})
81+
}
82+
}

0 commit comments

Comments
 (0)