use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum ProxyMode {
#[default]
Off,
Required {
versions: ProxyVersions,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProxyVersions {
V1,
V2,
Both,
}
#[derive(Clone, Copy)]
pub struct ProxyFacts {
alpn: [u8; 32],
alpn_len: u8,
authority: [u8; 255],
authority_len: u8,
unique_id: [u8; 128],
unique_id_len: u8,
ssl_client: Option<u8>,
}
impl Default for ProxyFacts {
fn default() -> ProxyFacts {
ProxyFacts {
alpn: [0; 32],
alpn_len: 0,
authority: [0; 255],
authority_len: 0,
unique_id: [0; 128],
unique_id_len: 0,
ssl_client: None,
}
}
}
impl ProxyFacts {
#[must_use]
pub fn alpn(&self) -> Option<&[u8]> {
(self.alpn_len > 0).then(|| &self.alpn[..usize::from(self.alpn_len)])
}
#[must_use]
pub fn authority(&self) -> Option<&str> {
if self.authority_len == 0 {
return None;
}
std::str::from_utf8(&self.authority[..usize::from(self.authority_len)]).ok()
}
#[must_use]
pub fn unique_id(&self) -> Option<&[u8]> {
(self.unique_id_len > 0).then(|| &self.unique_id[..usize::from(self.unique_id_len)])
}
#[must_use]
pub fn ssl_client(&self) -> Option<u8> {
self.ssl_client
}
}
impl fmt::Debug for ProxyFacts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ProxyFacts")
.field("alpn", &self.alpn().map(String::from_utf8_lossy))
.field("authority", &self.authority())
.field("unique_id_len", &self.unique_id_len)
.field("ssl_client", &self.ssl_client)
.finish()
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProxyError {
OutputTooSmall {
need: usize,
},
NotProxy,
V1TooLong,
V1Syntax {
at: u8,
},
V1BadAddress,
V1BadPort,
V2BadVersion,
V2BadCommand,
V2BadFamily,
V2LengthTooLarge {
declared: u16,
max: u16,
},
V2AddressTooShort,
V2TlvOverrun,
V2CrcMismatch,
V2UniqueIdTooLong,
V2SslMalformed,
FamilyMismatch,
}
impl fmt::Display for ProxyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ProxyError::OutputTooSmall { need } => {
write!(f, "output buffer too small ({need} bytes needed)")
}
ProxyError::NotProxy => f.write_str("the connection did not start with a PROXY header"),
ProxyError::V1TooLong => f.write_str("v1 header longer than 107 bytes"),
ProxyError::V1Syntax { at } => write!(f, "v1 header syntax error at byte {at}"),
ProxyError::V1BadAddress => f.write_str("v1 header with an invalid address"),
ProxyError::V1BadPort => f.write_str("v1 header with an invalid port"),
ProxyError::V2BadVersion => f.write_str("v2 header with an unknown version"),
ProxyError::V2BadCommand => f.write_str("v2 header with an unknown command"),
ProxyError::V2BadFamily => f.write_str("v2 header with an unknown address family"),
ProxyError::V2LengthTooLarge { declared, max } => {
write!(
f,
"v2 header declares {declared} bytes, above the maximum of {max}"
)
}
ProxyError::V2AddressTooShort => {
f.write_str("v2 address block too short for its family")
}
ProxyError::V2TlvOverrun => f.write_str("v2 TLV runs past the declared length"),
ProxyError::V2CrcMismatch => f.write_str("v2 header checksum does not match"),
ProxyError::V2UniqueIdTooLong => f.write_str("v2 unique id longer than 128 bytes"),
ProxyError::V2SslMalformed => f.write_str("v2 SSL TLV is malformed"),
ProxyError::FamilyMismatch => f.write_str("addresses do not match the declared family"),
}
}
}
impl std::error::Error for ProxyError {}