pub mod protocol_parser;
pub mod protocol_composer;
use core::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::{HaProxRes, map_error, protocol_raw, return_error};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProtocolV1Inet
{
Tcp4, Tcp6, None
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HapProtoV1
{
TCP4
{
src_addr: Ipv4Addr,
dst_addr: Ipv4Addr,
src_port: u16,
dst_port: u16,
},
TCP6
{
src_addr: Ipv6Addr,
dst_addr: Ipv6Addr,
src_port: u16,
dst_port: u16,
},
UNKNOWN,
}
impl fmt::Display for HapProtoV1
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
let s: String = self.into();
write!(f, "{}", s)
}
}
impl From<&HapProtoV1> for String
{
fn from(value: &HapProtoV1) -> Self
{
match value
{
HapProtoV1::TCP4{ src_addr, dst_addr, src_port, dst_port } =>
{
let out =
[
protocol_raw::HEADER_MAGIC_V1_STR, protocol_raw::HEADER_V1_WSPACE,
protocol_raw::HEADER_V1_INET_TCP4, protocol_raw::HEADER_V1_WSPACE,
src_addr.to_string().as_str(), protocol_raw::HEADER_V1_WSPACE,
dst_addr.to_string().as_str(), protocol_raw::HEADER_V1_WSPACE,
src_port.to_string().as_str(), protocol_raw::HEADER_V1_WSPACE,
dst_port.to_string().as_str(), protocol_raw::HEADER_V1_EOM
]
.concat();
return out;
},
HapProtoV1::TCP6{ src_addr, dst_addr, src_port, dst_port } =>
{
let out =
[
protocol_raw::HEADER_MAGIC_V1_STR, protocol_raw::HEADER_V1_WSPACE,
protocol_raw::HEADER_V1_INET_TCP6, protocol_raw::HEADER_V1_WSPACE,
src_addr.segments().iter().map(|v| format!("{:04x}", v)).collect::<Vec<String>>().join(":").as_str(), protocol_raw::HEADER_V1_WSPACE,
dst_addr.segments().iter().map(|v| format!("{:04x}", v)).collect::<Vec<String>>().join(":").as_str(), protocol_raw::HEADER_V1_WSPACE,
src_port.to_string().as_str(), protocol_raw::HEADER_V1_WSPACE,
dst_port.to_string().as_str(), protocol_raw::HEADER_V1_EOM
]
.concat();
return out;
},
HapProtoV1::UNKNOWN =>
{
let out =
[
protocol_raw::HEADER_MAGIC_V1_STR, protocol_raw::HEADER_V1_WSPACE,
protocol_raw::HEADER_V1_INET_UNKNWON, protocol_raw::HEADER_V1_EOM
]
.concat();
return out;
}
}
}
}
impl From<HapProtoV1> for String
{
fn from(value: HapProtoV1) -> Self
{
return (&value).into();
}
}
impl HapProtoV1
{
pub(super)
fn unknown() -> Self
{
return Self::UNKNOWN;
}
pub(super)
fn from_ip_port(
src_ip: IpAddr,
dst_ip: IpAddr,
src_port: u16,
dst_port: u16
) -> HaProxRes<Self>
{
if src_ip.is_ipv4() == true
{
let IpAddr::V4(dst_addr) = dst_ip
else
{
return_error!(ArgumentEinval, "dst_addr is not IPv4");
};
let IpAddr::V4(src_addr) = src_ip
else
{
return_error!(ArgumentEinval, "src_addr is not IPv4");
};
return Ok(
Self::TCP4{ src_addr, dst_addr, src_port, dst_port }
)
}
else
{
let IpAddr::V6(src_addr) = src_ip
else
{
return_error!(ArgumentEinval, "src_addr is not IPv6");
};
let IpAddr::V6(dst_addr) = dst_ip
else
{
return_error!(ArgumentEinval, "dst_addr is not IPv6");
};
return Ok(
Self::TCP6{ src_addr, dst_addr, src_port, dst_port }
)
}
}
pub
fn from_raw(
inet: &str,
src_ip: Option<&str>,
dst_ip: Option<&str>,
src_port: Option<&str>,
dst_port: Option<&str>
) -> HaProxRes<Self>
{
if inet == protocol_raw::HEADER_V1_INET_UNKNWON
{
return Ok(Self::UNKNOWN);
}
if src_ip.is_none() == true || dst_ip.is_none() == true ||
src_port.is_none() == true || dst_port.is_none() == true
{
return_error!(MalformedData, "missing field/s '{:?}' '{:?}' '{:?}' '{:?}'",
src_ip, dst_ip, src_port, dst_port);
}
if inet == protocol_raw::HEADER_V1_INET_TCP4
{
return Ok(
Self::TCP4
{
src_addr:
src_ip.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse src_addr '{}' err: '{}", src_ip.unwrap(), e)
)?,
dst_addr:
dst_ip.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse dst_addr '{}' err: '{}", dst_ip.unwrap(), e)
)?,
src_port:
src_port.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse src_port '{}' err: '{}", src_port.unwrap(), e)
)?,
dst_port:
dst_port.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse dst_port '{}' err: '{}", dst_port.unwrap(), e)
)?
}
);
}
else if inet == protocol_raw::HEADER_V1_INET_TCP6
{
return Ok(
Self::TCP6
{
src_addr:
src_ip.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse src_addr '{}' err: '{}", src_ip.unwrap(), e)
)?,
dst_addr:
dst_ip.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse dst_addr '{}' err: '{}", dst_ip.unwrap(), e)
)?,
src_port:
src_port.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse src_port '{}' err: '{}", src_port.unwrap(), e)
)?,
dst_port:
dst_port.as_ref().unwrap().parse().map_err(|e|
map_error!(MalformedData, "cannot parse dst_port '{}' err: '{}", dst_port.unwrap(), e)
)?
}
);
}
else
{
return_error!(MalformedData, "unknown INET: '{}'", inet);
}
}
pub
fn get_src_addr(&self) -> Option<IpAddr>
{
match self
{
Self::TCP4 { src_addr, .. } =>
return Some(IpAddr::V4(*src_addr)),
Self::TCP6 { src_addr, .. } =>
return Some(IpAddr::V6(*src_addr)),
Self::UNKNOWN =>
return None,
}
}
pub
fn get_dst_addr(&self) -> Option<IpAddr>
{
match self
{
Self::TCP4 { dst_addr, .. } =>
return Some(IpAddr::V4(*dst_addr)),
Self::TCP6 { dst_addr, .. } =>
return Some(IpAddr::V6(*dst_addr)),
Self::UNKNOWN =>
return None,
}
}
pub
fn get_src_port(&self) -> Option<u16>
{
match self
{
Self::TCP4 { src_port, .. } =>
return Some(*src_port),
Self::TCP6 { src_port, .. } =>
return Some(*src_port),
Self::UNKNOWN =>
return None,
}
}
pub
fn get_dst_port(&self) -> Option<u16>
{
match self
{
Self::TCP4 { dst_port, .. } =>
return Some(*dst_port),
Self::TCP6 { dst_port, .. } =>
return Some(*dst_port),
Self::UNKNOWN =>
return None,
}
}
pub
fn get_inet(&self) -> ProtocolV1Inet
{
match self
{
Self::TCP4{ .. } =>
return ProtocolV1Inet::Tcp4,
Self::TCP6 { .. } =>
return ProtocolV1Inet::Tcp6,
Self::UNKNOWN =>
return ProtocolV1Inet::None
}
}
}
#[cfg(test)]
mod tests_proto
{
use crate::HapProtoV1;
#[test]
fn simple_test1()
{
let s: String =
HapProtoV1::TCP4
{
src_addr: "255.255.255.255".parse().unwrap(),
dst_addr: "255.255.255.255".parse().unwrap(),
src_port: 65535,
dst_port: 65535
}
.into();
assert_eq!(s.as_str(), "PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n");
}
#[test]
fn simple_test2()
{
let s: String =
HapProtoV1::TCP4
{
src_addr: "192.168.1.1".parse().unwrap(),
dst_addr: "10.8.0.1".parse().unwrap(),
src_port: 23456,
dst_port: 12345
}
.into();
assert_eq!(s.as_str(), "PROXY TCP4 192.168.1.1 10.8.0.1 23456 12345\r\n");
}
#[test]
fn simple_test3()
{
let s: String =
HapProtoV1::TCP6
{
src_addr: "0acf:5d35:b4c4:731c:2442:2f17:c6f9:5b7f".parse().unwrap(),
dst_addr: "4d7f:8980:38d6:e0c3:7301:70e9:f8ef:e393".parse().unwrap(),
src_port: 23456,
dst_port: 12345
}
.into();
assert_eq!(s.as_str(), "PROXY TCP6 0acf:5d35:b4c4:731c:2442:2f17:c6f9:5b7f 4d7f:8980:38d6:e0c3:7301:70e9:f8ef:e393 23456 12345\r\n");
}
#[test]
fn simple_test4()
{
let s: String =
HapProtoV1::TCP6
{
src_addr: "0acf:5d35:b4c4:0000:2442:2f17:c6f9:5b7f".parse().unwrap(),
dst_addr: "4d7f:8980:38d6:e0c3:7301:70e9:f8ef:e393".parse().unwrap(),
src_port: 23456,
dst_port: 12345
}
.into();
assert_eq!(s.as_str(), "PROXY TCP6 0acf:5d35:b4c4:0000:2442:2f17:c6f9:5b7f 4d7f:8980:38d6:e0c3:7301:70e9:f8ef:e393 23456 12345\r\n");
}
#[test]
fn simple_test5()
{
let s: String =
HapProtoV1::UNKNOWN.into();
assert_eq!(s.as_str(), "PROXY UNKNOWN\r\n");
}
}