use crate::ip::{IPv4, IPv6};
use std::borrow::Cow;
use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
pub const PROTOCOL_PREFIX: &str = "PROXY";
pub const PROTOCOL_SUFFIX: &str = "\r\n";
pub const TCP4: &str = "TCP4";
pub const TCP6: &str = "TCP6";
pub const UNKNOWN: &str = "UNKNOWN";
pub const SEPARATOR: char = ' ';
#[derive(Clone, Debug, PartialEq)]
pub struct Header<'a> {
pub header: Cow<'a, str>,
pub addresses: Addresses,
}
impl<'a> Header<'a> {
pub fn new<H: Into<&'a str>, A: Into<Addresses>>(header: H, addresses: A) -> Self {
Header {
header: Cow::Borrowed(header.into()),
addresses: addresses.into(),
}
}
pub fn to_owned(&self) -> Header<'static> {
Header {
header: Cow::Owned::<'static>(self.header.to_string()),
addresses: self.addresses,
}
}
pub fn protocol(&self) -> &str {
self.addresses.protocol()
}
pub fn addresses_str(&self) -> &str {
let start = PROTOCOL_PREFIX.len() + SEPARATOR.len_utf8() + self.protocol().len();
let end = self.header.len() - PROTOCOL_SUFFIX.len();
let addresses = &self.header[start..end];
if addresses.starts_with(SEPARATOR) {
&addresses[SEPARATOR.len_utf8()..]
} else {
addresses
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Addresses {
Unknown,
Tcp4(IPv4),
Tcp6(IPv6),
}
impl Addresses {
pub fn new_tcp4<T: Into<Ipv4Addr>>(
source_address: T,
destination_address: T,
source_port: u16,
destination_port: u16,
) -> Self {
Addresses::Tcp4(IPv4 {
source_address: source_address.into(),
source_port,
destination_address: destination_address.into(),
destination_port,
})
}
pub fn new_tcp6<T: Into<Ipv6Addr>>(
source_address: T,
destination_address: T,
source_port: u16,
destination_port: u16,
) -> Self {
Addresses::Tcp6(IPv6 {
source_address: source_address.into(),
source_port,
destination_address: destination_address.into(),
destination_port,
})
}
pub fn protocol(&self) -> &str {
match self {
Addresses::Tcp4(..) => TCP4,
Addresses::Tcp6(..) => TCP6,
Addresses::Unknown => UNKNOWN,
}
}
}
impl Default for Addresses {
fn default() -> Self {
Addresses::Unknown
}
}
impl From<(SocketAddr, SocketAddr)> for Addresses {
fn from(addresses: (SocketAddr, SocketAddr)) -> Self {
match addresses {
(SocketAddr::V4(source), SocketAddr::V4(destination)) => Addresses::Tcp4(IPv4::new(
*source.ip(),
*destination.ip(),
source.port(),
destination.port(),
)),
(SocketAddr::V6(source), SocketAddr::V6(destination)) => Addresses::Tcp6(IPv6::new(
*source.ip(),
*destination.ip(),
source.port(),
destination.port(),
)),
_ => Addresses::Unknown,
}
}
}
impl From<IPv4> for Addresses {
fn from(addresses: IPv4) -> Self {
Addresses::Tcp4(addresses)
}
}
impl From<IPv6> for Addresses {
fn from(addresses: IPv6) -> Self {
Addresses::Tcp6(addresses)
}
}
impl<'a> fmt::Display for Header<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.header.as_ref())
}
}
impl fmt::Display for Addresses {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unknown => f.write_str("PROXY UNKNOWN\r\n"),
Self::Tcp4(a) => write!(
f,
"PROXY TCP4 {} {} {} {}\r\n",
a.source_address, a.destination_address, a.source_port, a.destination_port
),
Self::Tcp6(a) => write!(
f,
"PROXY TCP6 {} {} {} {}\r\n",
a.source_address, a.destination_address, a.source_port, a.destination_port
),
}
}
}