source: code/trunk/vendor/github.com/pires/go-proxyproto/tlv.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

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