21#include <sys/socket.h>
24#include <netinet/in.h>
27#include <netinet/ip.h>
36 static const auto magic =
new SBuf(
"PROXY", 5);
52 static const auto magic =
new SBuf(
"\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
70 if (!
tok.prefix(ip, ipChars))
71 throw TexcHere(
"PROXY/1.0 error: malformed IP address");
74 throw TexcHere(
"PROXY/1.0 error: garbage after IP address");
77 throw TexcHere(
"PROXY/1.0 error: invalid IP address");
86 if (!
tok.int64(
port, 10,
false))
87 throw TexcHere(
"PROXY/1.0 error: malformed port");
89 if (trailingSpace && !
tok.skip(
' '))
90 throw TexcHere(
"PROXY/1.0 error: garbage after port");
92 if (
port > std::numeric_limits<uint16_t>::max())
93 throw TexcHere(
"PROXY/1.0 error: invalid port");
95 addr.
port(
static_cast<uint16_t
>(
port));
101 static const CharacterSet addressFamilies(
"Address family",
"46");
102 SBuf parsedAddressFamily;
104 if (!
tok.prefix(parsedAddressFamily, addressFamilies, 1))
105 throw TexcHere(
"PROXY/1.0 error: missing or invalid IP address family");
108 throw TexcHere(
"PROXY/1.0 error: missing SP after the IP address family");
114 if (header->addressFamily() != parsedAddressFamily)
115 throw TexcHere(
"PROXY/1.0 error: declared and/or actual IP address families mismatch");
128 static const auto maxInteriorLength = maxHeaderLength -
Magic().length() - 2;
132 if (!(
tok.prefix(interior, interiorChars, maxInteriorLength) &&
138 throw TexcHere(
"PROXY/1.0 error: malformed header");
142 static const SBuf v1(
"1.0");
147 if (!interiorTok.
skip(
' '))
148 throw TexcHere(
"PROXY/1.0 error: missing SP after the magic sequence");
150 static const SBuf protoUnknown(
"UNKNOWN");
151 static const SBuf protoTcp(
"TCP");
153 if (interiorTok.
skip(protoTcp))
155 else if (interiorTok.
skip(protoUnknown))
156 header->ignoreAddresses();
158 throw TexcHere(
"PROXY/1.0 error: invalid INET protocol or family");
169 header->sourceAddress =
tok.inet4(
"src_addr IPv4");
170 header->destinationAddress =
tok.inet4(
"dst_addr IPv4");
171 header->sourceAddress.port(
tok.uint16(
"src_port"));
172 header->destinationAddress.port(
tok.uint16(
"dst_port"));
177 header->sourceAddress =
tok.inet6(
"src_addr IPv6");
178 header->destinationAddress =
tok.inet6(
"dst_addr IPv6");
179 header->sourceAddress.port(
tok.uint16(
"src_port"));
180 header->destinationAddress.port(
tok.uint16(
"dst_port"));
186 tok.skip(216,
"unix_addr");
200 while (!
tok.atEnd()) {
201 const auto type =
tok.uint8(
"pp2_tlv::type");
202 header->tlvs.emplace_back(type,
tok.pstring16(
"pp2_tlv::value"));
211 const auto versionAndCommand = tokHeader.
uint8(
"version and command");
213 const auto version = (versionAndCommand & 0xF0) >> 4;
217 const auto command = (versionAndCommand & 0x0F);
219 throw TexcHere(
ToSBuf(
"PROXY/2.0 error: invalid command ", command));
221 const auto familyAndProto = tokHeader.
uint8(
"family and proto");
223 const auto family = (familyAndProto & 0xF0) >> 4;
225 throw TexcHere(
ToSBuf(
"PROXY/2.0 error: invalid address family ", family));
227 const auto proto = (familyAndProto & 0x0F);
229 throw TexcHere(
ToSBuf(
"PROXY/2.0 error: invalid transport protocol ", proto));
231 const auto rawHeader = tokHeader.
pstring16(
"header");
233 static const SBuf v2(
"2.0");
237 header->ignoreAddresses();
242 ParseAddresses(family, leftoverTok, header);
244 if (header->hasForwardedAddresses())
257 magicTok.
skip(Two::Magic()) ? &Two::Parse :
258 magicTok.
skip(One::Magic()) ? &One::Parse :
262 const auto parsed = (parser)(magicTok.
remaining());
267 if (buf.
length() >= Two::Magic().length()) {
270 throw TexcHere(
"PROXY protocol error: invalid magic");
281 header(parsedHeader),
284 assert(
bool(parsedHeader));
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
optimized set of C chars, with quick membership test and merge support
CharacterSet complement(const char *complementLabel=nullptr) const
CharacterSet & rename(const char *label)
change name; handy in const declarations that use operators
static const CharacterSet HEXDIG
static const CharacterSet CR
bool GetHostByName(const char *s)
unsigned short port() const
uint64_t parsed() const
the number of already parsed bytes
uint8_t uint8(const char *description)
parse a single-byte unsigned integer
SBuf pstring16(const char *description)
up to 64 KiB-long p-string
::Parser::InsufficientInput InsufficientInput
SBuf::size_type parsedSize() const
number of parsed bytes, including skipped ones
const SBuf & remaining() const
the remaining unprocessed section of buffer
bool skip(const SBuf &tokenToSkip)
successful parsing result
Parsed(const HeaderPointer &parsedHeader, const size_t parsedSize)
size_type length() const
Returns the number of bytes stored in SBuf.
MemBlob::size_type size_type
static Parsed Parse(const SBuf &buf)
extracts PROXY protocol v1 header from the given buffer
static void ExtractPort(Parser::Tokenizer &tok, Ip::Address &addr, const bool trailingSpace)
static const auto & Magic()
magic octet prefix for PROXY protocol version 1
static void ExtractIp(Parser::Tokenizer &tok, Ip::Address &addr)
static void ParseAddresses(Parser::Tokenizer &tok, Header::Pointer &header)
static void ParseTLVs(Parser::BinaryTokenizer &tok, Header::Pointer &header)
Command
PROXY protocol 'command' field value.
static void ParseAddresses(const uint8_t family, Parser::BinaryTokenizer &tok, Header::Pointer &header)
static Parsed Parse(const SBuf &buf)
extracts PROXY protocol v2 header from the given buffer
static const auto & Magic()
magic octet prefix for PROXY protocol version 2
@ afUnspecified
corresponds to a local connection or an unsupported protocol family
Parsed Parse(const SBuf &)
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf