proxy-protocol-codec

PROXY Protocol codec implementation in Rust. See HAProxy for the protocol specification.
Usage
Add the following to your Cargo.toml
as a dependency:
proxy-protocol-codec = "0.1"
Encoding
let address_pair = proxy_protocol_codec::v1::AddressPair::Inet {
src_ip: "127.0.0.1".parse().unwrap(),
dst_ip: "127.0.0.2".parse().unwrap(),
src_port: 8080,
dst_port: 80,
};
let header = proxy_protocol_codec::v1::Header::new(address_pair);
assert_eq!(header.encode(), "PROXY TCP4 127.0.0.1 127.0.0.2 8080 80\r\n");
let address_pair = proxy_protocol_codec::v1::AddressPair::Inet6 {
src_ip: "::1".parse().unwrap(),
dst_ip: "::2".parse().unwrap(),
src_port: 8080,
dst_port: 80,
};
let header = proxy_protocol_codec::v1::Header::new(address_pair);
assert_eq!(header.encode(), "PROXY TCP6 ::1 ::2 8080 80\r\n");
let address_pair = proxy_protocol_codec::v1::AddressPair::Unspecified;
let header = proxy_protocol_codec::v1::Header::new(address_pair);
assert_eq!(header.encode(), "PROXY UNKNOWN\r\n");
let header = proxy_protocol_codec::v2::Header::new_proxy(
proxy_protocol_codec::v2::Protocol::Stream,
proxy_protocol_codec::v2::AddressPair::Inet {
src_ip: "127.0.0.1".parse().unwrap(),
dst_ip: "127.0.0.2".parse().unwrap(),
src_port: 8080,
dst_port: 80,
},
);
let encoded = header
.encode()
.write_ext_authority(b"example.com")? .finish()?;
Decoding
let encoded = ...;
proxy_protocol_codec::v1::Header::decode(encoded))?
let tcp_stream = ...;
let mut buf = Vec::with_capacity(proxy_protocol_codec::v2::HEADER_SIZE);
unsafe {
buf.set_len(proxy_protocol_codec::v2::HEADER_SIZE);
}
let peeked = tcp_stream.peek(&mut buf[..])?;
if peeked != 16 {
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"Not enough data to decode PROXY Protocol v2 header",
));
}
match proxy_protocol_codec::v2::Header::decode(&buf[..])? {
proxy_protocol_codec::v2::Decoded::Partial(remaining) => {
let total_length = proxy_protocol_codec::v2::HEADER_SIZE + remaining.get();
unsafe {
buf.set_len(total_length);
}
tcp_stream.read_exact(
&mut buf[proxy_protocol_codec::v2::HEADER_SIZE..proxy_protocol_codec::v2::HEADER_SIZE + remaining.get()]
)?;
let proxy_protocol_codec::v2::Decoded::Some(header) = proxy_protocol_codec::v2::Header::decode(&buf[..])? else {
panic!("must be Some here");
};
header
}
proxy_protocol_codec::v2::Decoded::Some(header) => {
header
}
proxy_protocol_codec::v2::Decoded::None => {
return ...;
}
}