use crate::protocol::ip::{IPv4, IPv6};
use crate::protocol::v2::error::ParseError;
use std::borrow::Cow;
use std::fmt;
use std::net::SocketAddr;
use std::ops::BitOr;
pub const PROTOCOL_PREFIX: &[u8] = b"\r\n\r\n\0\r\nQUIT\n";
pub(crate) const MINIMUM_LENGTH: usize = 16;
pub(crate) const MINIMUM_TLV_LENGTH: usize = 3;
const IPV4_ADDRESSES_BYTES: usize = 12;
const IPV6_ADDRESSES_BYTES: usize = 36;
const UNIX_ADDRESSES_BYTES: usize = 216;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Header<'a> {
pub header: Cow<'a, [u8]>,
pub version: Version,
pub command: Command,
pub protocol: Protocol,
pub addresses: Addresses,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Version {
Two = 0x20,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Command {
Local = 0,
Proxy,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum AddressFamily {
Unspecified = 0x00,
IPv4 = 0x10,
IPv6 = 0x20,
Unix = 0x30,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Protocol {
Unspecified = 0,
Stream,
Datagram,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Addresses {
Unspecified,
IPv4(IPv4),
IPv6(IPv6),
Unix(Unix),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Unix {
pub source: [u8; 108],
pub destination: [u8; 108],
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct TypeLengthValues<'a> {
bytes: &'a [u8],
offset: usize,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TypeLengthValue<'a> {
pub kind: Type,
pub value: Cow<'a, [u8]>,
}
rama_utils::macros::enums::enum_builder! {
@U8
pub enum Type {
ALPN => 0x01,
Authority => 0x02,
CRC32C => 0x03,
NoOp => 0x04,
UniqueId => 0x05,
SSL => 0x20,
SSLVersion => 0x21,
SSLCommonName => 0x22,
SSLCipher => 0x23,
SSLSignatureAlgorithm => 0x24,
SSLKeyAlgorithm => 0x25,
NetworkNamespace => 0x30,
}
}
impl fmt::Display for Header<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:?} {:#X} {:#X} ({} bytes)",
PROTOCOL_PREFIX,
self.version | self.command,
self.protocol | self.address_family(),
self.length()
)
}
}
impl Header<'_> {
#[must_use]
pub fn to_owned(&self) -> Header<'static> {
Header {
header: Cow::Owned(self.header.to_vec()),
version: self.version,
command: self.command,
protocol: self.protocol,
addresses: self.addresses,
}
}
#[must_use]
pub fn length(&self) -> usize {
self.header[MINIMUM_LENGTH..].len()
}
#[must_use]
pub fn len(&self) -> usize {
self.header.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.header.is_empty()
}
#[must_use]
pub fn address_family(&self) -> AddressFamily {
self.addresses.address_family()
}
fn address_bytes_end(&self) -> usize {
let length = self.length();
let address_bytes = self.address_family().byte_length().unwrap_or(length);
MINIMUM_LENGTH + std::cmp::min(address_bytes, length)
}
#[must_use]
pub fn address_bytes(&self) -> &[u8] {
&self.header[MINIMUM_LENGTH..self.address_bytes_end()]
}
#[must_use]
pub fn tlv_bytes(&self) -> &[u8] {
&self.header[self.address_bytes_end()..]
}
#[must_use]
pub fn tlvs(&self) -> TypeLengthValues<'_> {
TypeLengthValues {
bytes: self.tlv_bytes(),
offset: 0,
}
}
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.header.as_ref()
}
#[must_use]
pub fn verify_crc32c(&self) -> Crc32cStatus {
let tlv_start = self.address_bytes_end();
let mut cursor = tlv_start;
for tlv in self.tlvs() {
let tlv = match tlv {
Ok(t) => t,
Err(e) => {
rama_core::telemetry::tracing::debug!(
error = %e,
"haproxy v2: TLV stream malformed before CRC32C TLV could be located",
);
return Crc32cStatus::MalformedBeforeCrc;
}
};
let value_start = cursor + MINIMUM_TLV_LENGTH;
let value_end = value_start + tlv.value.len();
if tlv.kind == Type::CRC32C {
let Ok(value) = <&[u8; 4]>::try_from(tlv.value.as_ref()) else {
rama_core::telemetry::tracing::debug!(
len = tlv.value.len(),
"haproxy v2: CRC32C TLV has unexpected value length (want 4)",
);
return Crc32cStatus::Invalid;
};
let expected = u32::from_be_bytes(*value);
let mut hasher = super::Crc32cHasher::new();
hasher.update(&self.header[..value_start]);
hasher.update(&[0u8; 4]);
hasher.update(&self.header[value_end..]);
return if hasher.finalize() == expected {
Crc32cStatus::Valid
} else {
Crc32cStatus::Invalid
};
}
cursor = value_end;
}
Crc32cStatus::Absent
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Crc32cStatus {
Absent,
Valid,
Invalid,
MalformedBeforeCrc,
}
impl TypeLengthValues<'_> {
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
self.bytes
}
}
impl<'a> From<&'a [u8]> for TypeLengthValues<'a> {
fn from(bytes: &'a [u8]) -> Self {
TypeLengthValues { bytes, offset: 0 }
}
}
impl<'a> Iterator for TypeLengthValues<'a> {
type Item = Result<TypeLengthValue<'a>, ParseError>;
fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.bytes.len() {
return None;
}
let remaining = &self.bytes[self.offset..];
if remaining.len() < MINIMUM_TLV_LENGTH {
self.offset = self.bytes.len();
return Some(Err(ParseError::Leftovers(self.bytes.len())));
}
let tlv_type = remaining[0];
let length = u16::from_be_bytes([remaining[1], remaining[2]]);
let tlv_length = MINIMUM_TLV_LENGTH + length as usize;
if remaining.len() < tlv_length {
self.offset = self.bytes.len();
return Some(Err(ParseError::InvalidTLV(tlv_type, length)));
}
self.offset += tlv_length;
Some(Ok(TypeLengthValue {
kind: Type::from(tlv_type),
value: Cow::Borrowed(&remaining[MINIMUM_TLV_LENGTH..tlv_length]),
}))
}
}
impl TypeLengthValues<'_> {
#[must_use]
pub fn len(&self) -> u16 {
self.bytes.len() as u16
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl BitOr<Command> for Version {
type Output = u8;
fn bitor(self, command: Command) -> Self::Output {
(self as u8) | (command as u8)
}
}
impl BitOr<Version> for Command {
type Output = u8;
fn bitor(self, version: Version) -> Self::Output {
(self as u8) | (version as u8)
}
}
impl BitOr<Protocol> for AddressFamily {
type Output = u8;
fn bitor(self, protocol: Protocol) -> Self::Output {
(self as u8) | (protocol as u8)
}
}
impl AddressFamily {
#[must_use]
pub fn byte_length(&self) -> Option<usize> {
match self {
Self::IPv4 => Some(IPV4_ADDRESSES_BYTES),
Self::IPv6 => Some(IPV6_ADDRESSES_BYTES),
Self::Unix => Some(UNIX_ADDRESSES_BYTES),
Self::Unspecified => None,
}
}
}
impl From<AddressFamily> for u16 {
fn from(address_family: AddressFamily) -> Self {
address_family.byte_length().unwrap_or_default() as Self
}
}
impl From<(SocketAddr, SocketAddr)> for Addresses {
fn from(addresses: (SocketAddr, SocketAddr)) -> Self {
match addresses {
(SocketAddr::V4(source), SocketAddr::V4(destination)) => Self::IPv4(IPv4::new(
*source.ip(),
*destination.ip(),
source.port(),
destination.port(),
)),
(SocketAddr::V6(source), SocketAddr::V6(destination)) => Self::IPv6(IPv6::new(
*source.ip(),
*destination.ip(),
source.port(),
destination.port(),
)),
_ => Self::Unspecified,
}
}
}
impl From<IPv4> for Addresses {
fn from(addresses: IPv4) -> Self {
Self::IPv4(addresses)
}
}
impl From<IPv6> for Addresses {
fn from(addresses: IPv6) -> Self {
Self::IPv6(addresses)
}
}
impl From<Unix> for Addresses {
fn from(addresses: Unix) -> Self {
Self::Unix(addresses)
}
}
impl Addresses {
#[must_use]
pub fn address_family(&self) -> AddressFamily {
match self {
Self::Unspecified => AddressFamily::Unspecified,
Self::IPv4(..) => AddressFamily::IPv4,
Self::IPv6(..) => AddressFamily::IPv6,
Self::Unix(..) => AddressFamily::Unix,
}
}
#[must_use]
pub fn len(&self) -> usize {
self.address_family().byte_length().unwrap_or_default()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.address_family().byte_length().is_none()
}
}
impl Unix {
#[must_use]
pub const fn new(source: [u8; 108], destination: [u8; 108]) -> Self {
Self {
source,
destination,
}
}
}
impl BitOr<AddressFamily> for Protocol {
type Output = u8;
fn bitor(self, address_family: AddressFamily) -> Self::Output {
(self as u8) | (address_family as u8)
}
}
impl<'a, T: Into<Type>> From<(T, &'a [u8])> for TypeLengthValue<'a> {
fn from((kind, value): (T, &'a [u8])) -> Self {
TypeLengthValue {
kind: kind.into(),
value: value.into(),
}
}
}
impl<'a> TypeLengthValue<'a> {
#[must_use]
pub fn to_owned(&self) -> TypeLengthValue<'static> {
TypeLengthValue {
kind: self.kind,
value: Cow::Owned(self.value.to_vec()),
}
}
pub fn new<T: Into<Type>>(kind: T, value: &'a [u8]) -> Self {
TypeLengthValue {
kind: kind.into(),
value: value.into(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.value.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.value.is_empty()
}
}