package proxyproto
import (
"encoding/binary"
"errors"
"fmt"
"math"
)
const (
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
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 = errors .New ("proxyproto: truncated TLV" )
ErrMalformedTLV = errors .New ("proxyproto: malformed TLV Value" )
ErrIncompatibleTLV = errors .New ("proxyproto: incompatible TLV type" )
)
type PP2Type byte
type TLV struct {
Type PP2Type
Value []byte
}
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 ]))
i += 3
if i +tlvLen > len (raw ) {
return nil , ErrTruncatedTLV
}
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
}
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
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
}
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
}
func (p PP2Type ) App () bool {
return p >= PP2_TYPE_MIN_CUSTOM && p <= PP2_TYPE_MAX_CUSTOM
}
func (p PP2Type ) Experiment () bool {
return p >= PP2_TYPE_MIN_EXPERIMENT && p <= PP2_TYPE_MAX_EXPERIMENT
}
func (p PP2Type ) Future () bool {
return p >= PP2_TYPE_MIN_FUTURE
}
func (p PP2Type ) Spec () bool {
return p .Registered () || p .App () || p .Experiment () || p .Future ()
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .