133 lines
3.2 KiB
Go
133 lines
3.2 KiB
Go
package proxyprotocol
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/binary"
|
|
"errors"
|
|
"net"
|
|
)
|
|
|
|
// Errors
|
|
var (
|
|
ErrUnknownVersion = errors.New("unknown version")
|
|
ErrUnknownCommand = errors.New("unknown command")
|
|
ErrUnexpectedAddressLen = errors.New("unexpected address length")
|
|
)
|
|
|
|
// Meta buffer byte position
|
|
const (
|
|
versionCommandPos = 0
|
|
protocolPos = 1
|
|
addressLenStartPos = 2
|
|
addressLenEndPos = 4
|
|
)
|
|
|
|
// BinaryHeaderParser parse proxyprotocol header from Reader
|
|
type BinaryHeaderParser struct {
|
|
logger Logger
|
|
}
|
|
|
|
// NewBinaryHeaderParser construct BinaryHeaderParser
|
|
func NewBinaryHeaderParser(logger Logger) BinaryHeaderParser {
|
|
return BinaryHeaderParser{
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Parse buffer
|
|
func (parser BinaryHeaderParser) Parse(buf *bufio.Reader) (*Header, error) {
|
|
magicBuf, err := buf.Peek(BinarySignatureLen)
|
|
if err != nil {
|
|
parser.logger.Printf("Read magic prefix error: %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
if !bytes.Equal(magicBuf, BinarySignature) {
|
|
return nil, ErrInvalidSignature
|
|
}
|
|
|
|
_, err = buf.Discard(BinarySignatureLen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
metaBuf := make([]byte, addressLenEndPos)
|
|
if _, err = buf.Read(metaBuf); err != nil {
|
|
parser.logger.Printf("Read meta error: %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
versionCommandByte := metaBuf[versionCommandPos]
|
|
|
|
if versionCommandByte&BinaryVersionMask != BinaryVersion2 {
|
|
return nil, ErrUnknownVersion
|
|
}
|
|
|
|
addressSizeBuf := metaBuf[addressLenStartPos:addressLenEndPos]
|
|
addressesLen := int(binary.BigEndian.Uint16(addressSizeBuf))
|
|
parser.logger.Printf("Addresses len: %d", addressesLen)
|
|
|
|
addressesBuf := make([]byte, addressesLen)
|
|
addressReaded, err := buf.Read(addressesBuf)
|
|
if err != nil {
|
|
parser.logger.Printf("Read address error: %s", err)
|
|
return nil, err
|
|
}
|
|
parser.logger.Printf("Address readed: %d", addressReaded)
|
|
|
|
switch versionCommandByte & BinaryCommandMask {
|
|
case BinaryCommandProxy:
|
|
return parserBinaryCommandHeader(metaBuf[protocolPos], addressesBuf)
|
|
case BinaryCommandLocal:
|
|
return nil, nil
|
|
default:
|
|
return nil, ErrUnknownCommand
|
|
}
|
|
}
|
|
|
|
func parserBinaryCommandHeader(protocol byte, addressesBuf []byte) (*Header, error) {
|
|
switch protocol & BinaryAFMask {
|
|
case BinaryProtocolUnspec:
|
|
return nil, nil
|
|
case BinaryAFInet:
|
|
return parseAddressData(addressesBuf, net.IPv4len)
|
|
case BinaryAFInet6:
|
|
return parseAddressData(addressesBuf, net.IPv6len)
|
|
default:
|
|
return nil, ErrUnknownProtocol
|
|
}
|
|
}
|
|
|
|
func parseAddressData(addressesBuf []byte, ipLen int) (*Header, error) {
|
|
expectedBufSize := 2 * (ipLen + BinaryPortLen)
|
|
if len(addressesBuf) < expectedBufSize {
|
|
return nil, ErrUnexpectedAddressLen
|
|
}
|
|
|
|
srcIP := make(net.IP, ipLen)
|
|
copy(srcIP, addressesBuf[:ipLen])
|
|
addressesBuf = addressesBuf[ipLen:]
|
|
|
|
dstIP := make(net.IP, ipLen)
|
|
copy(dstIP, addressesBuf[:ipLen])
|
|
addressesBuf = addressesBuf[ipLen:]
|
|
|
|
srcPort := binary.BigEndian.Uint16(addressesBuf[:BinaryPortLen])
|
|
addressesBuf = addressesBuf[BinaryPortLen:]
|
|
|
|
dstPort := binary.BigEndian.Uint16(addressesBuf[:BinaryPortLen])
|
|
// addressesBuf = addressesBuf[BinaryPortLen:]
|
|
|
|
return &Header{
|
|
SrcAddr: &net.TCPAddr{
|
|
IP: srcIP,
|
|
Port: int(srcPort),
|
|
},
|
|
DstAddr: &net.TCPAddr{
|
|
IP: dstIP,
|
|
Port: int(dstPort),
|
|
},
|
|
}, nil
|
|
}
|