-
-
Notifications
You must be signed in to change notification settings - Fork 127
Expand file tree
/
Copy pathtlv.go
More file actions
144 lines (130 loc) · 4.14 KB
/
tlv.go
File metadata and controls
144 lines (130 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Type-Length-Value splitting and parsing for proxy protocol V2
// See spec https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt sections 2.2 to 2.7 and
package proxyproto
import (
"encoding/binary"
"errors"
"fmt"
"math"
)
// TLV type constants defined by the PROXY protocol spec.
//
//nolint:revive // Names follow the spec.
const (
// Section 2.2.
PP2_TYPE_ALPN PP2Type = 0x01
PP2_TYPE_AUTHORITY PP2Type = 0x02
PP2_TYPE_CRC32C PP2Type = 0x03
PP2_TYPE_NOOP PP2Type = 0x04
PP2_TYPE_UNIQUE_ID PP2Type = 0x05
PP2_TYPE_SSL PP2Type = 0x20
PP2_SUBTYPE_SSL_VERSION PP2Type = 0x21
PP2_SUBTYPE_SSL_CN PP2Type = 0x22
PP2_SUBTYPE_SSL_CIPHER PP2Type = 0x23
PP2_SUBTYPE_SSL_SIG_ALG PP2Type = 0x24
PP2_SUBTYPE_SSL_KEY_ALG PP2Type = 0x25
PP2_SUBTYPE_SSL_GROUP PP2Type = 0x26
PP2_SUBTYPE_SSL_SIG_SCHEME PP2Type = 0x27
PP2_SUBTYPE_SSL_CLIENT_CERT PP2Type = 0x28
PP2_TYPE_NETNS PP2Type = 0x30
// Section 2.2.7, reserved types.
PP2_TYPE_MIN_CUSTOM PP2Type = 0xE0
PP2_TYPE_MAX_CUSTOM PP2Type = 0xEF
PP2_TYPE_MIN_EXPERIMENT PP2Type = 0xF0
PP2_TYPE_MAX_EXPERIMENT PP2Type = 0xF7
PP2_TYPE_MIN_FUTURE PP2Type = 0xF8
PP2_TYPE_MAX_FUTURE PP2Type = 0xFF
)
var (
// ErrTruncatedTLV indicates a TLV was truncated.
ErrTruncatedTLV = errors.New("proxyproto: truncated TLV")
// ErrMalformedTLV indicates a TLV has malformed data.
ErrMalformedTLV = errors.New("proxyproto: malformed TLV Value")
// ErrIncompatibleTLV indicates a TLV is of an unexpected type.
ErrIncompatibleTLV = errors.New("proxyproto: incompatible TLV type")
)
// PP2Type is the proxy protocol v2 type.
type PP2Type byte
// TLV is a uninterpreted Type-Length-Value for V2 protocol, see section 2.2.
type TLV struct {
Type PP2Type
Value []byte
}
// SplitTLVs splits the Type-Length-Value vector, returns the vector or an error.
func SplitTLVs(raw []byte) ([]TLV, error) {
var tlvs []TLV
for i := 0; i < len(raw); {
tlv := TLV{
Type: PP2Type(raw[i]),
}
if len(raw)-i <= 2 {
return nil, ErrTruncatedTLV
}
tlvLen := int(binary.BigEndian.Uint16(raw[i+1 : i+3])) // Max length = 65K
i += 3
if i+tlvLen > len(raw) {
return nil, ErrTruncatedTLV
}
// Ignore no-op padding
if tlv.Type != PP2_TYPE_NOOP {
tlv.Value = make([]byte, tlvLen)
copy(tlv.Value, raw[i:i+tlvLen])
}
i += tlvLen
tlvs = append(tlvs, tlv)
}
return tlvs, nil
}
// JoinTLVs joins multiple Type-Length-Value records.
func JoinTLVs(tlvs []TLV) ([]byte, error) {
var raw []byte
for _, tlv := range tlvs {
if len(tlv.Value) > math.MaxUint16 {
return nil, fmt.Errorf("proxyproto: cannot format TLV %v with length %d", tlv.Type, len(tlv.Value))
}
var length [2]byte
//nolint:gosec // lengthValue is validated above.
lengthValue := uint16(len(tlv.Value))
binary.BigEndian.PutUint16(length[:], lengthValue)
raw = append(raw, byte(tlv.Type))
raw = append(raw, length[:]...)
raw = append(raw, tlv.Value...)
}
return raw, nil
}
// Registered is true if the type is registered in the spec, see section 2.2.
func (p PP2Type) Registered() bool {
switch p {
case PP2_TYPE_ALPN,
PP2_TYPE_AUTHORITY,
PP2_TYPE_CRC32C,
PP2_TYPE_NOOP,
PP2_TYPE_UNIQUE_ID,
PP2_TYPE_SSL,
PP2_SUBTYPE_SSL_VERSION,
PP2_SUBTYPE_SSL_CN,
PP2_SUBTYPE_SSL_CIPHER,
PP2_SUBTYPE_SSL_SIG_ALG,
PP2_SUBTYPE_SSL_KEY_ALG,
PP2_TYPE_NETNS:
return true
}
return false
}
// App is true if the type is reserved for application specific data, see section 2.2.7.
func (p PP2Type) App() bool {
return p >= PP2_TYPE_MIN_CUSTOM && p <= PP2_TYPE_MAX_CUSTOM
}
// Experiment is true if the type is reserved for temporary experimental use by application
// developers, see section 2.2.7.
func (p PP2Type) Experiment() bool {
return p >= PP2_TYPE_MIN_EXPERIMENT && p <= PP2_TYPE_MAX_EXPERIMENT
}
// Future is true is the type is reserved for future use, see section 2.2.7.
func (p PP2Type) Future() bool {
return p >= PP2_TYPE_MIN_FUTURE
}
// Spec is true if the type is covered by the spec, see section 2.2 and 2.2.7.
func (p PP2Type) Spec() bool {
return p.Registered() || p.App() || p.Experiment() || p.Future()
}