use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
use crate::ffi::pfvar::pfsync_state_host;
use crate::{Direction, Proto, ffi::pfvar::pfsync_state};
use crate::{Error, ErrorInternal, Result};
#[derive(Clone)]
pub struct State {
sync_state: pfsync_state,
}
impl fmt::Debug for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("State")
.field("direction", &self.direction())
.field("proto", &self.proto())
.field("local_address", &self.local_address())
.field("remote_address", &self.remote_address())
.finish()
}
}
impl State {
pub(crate) unsafe fn new(sync_state: pfsync_state) -> State {
State { sync_state }
}
pub fn direction(&self) -> Result<Direction> {
Direction::try_from(self.sync_state.direction)
}
pub fn proto(&self) -> Result<Proto> {
Proto::try_from(self.sync_state.proto)
}
pub fn local_address(&self) -> Result<SocketAddr> {
unsafe { parse_address(self.sync_state.af_lan, self.sync_state.lan) }
}
pub fn remote_address(&self) -> Result<SocketAddr> {
unsafe { parse_address(self.sync_state.af_lan, self.sync_state.ext_lan) }
}
pub(crate) fn as_raw(&self) -> &pfsync_state {
&self.sync_state
}
}
unsafe fn parse_address(family: u8, host: pfsync_state_host) -> Result<SocketAddr> {
let ip = match u32::from(family) {
crate::ffi::pfvar::PF_INET => {
Ipv4Addr::from(u32::from_be(unsafe { host.addr.pfa._v4addr.s_addr })).into()
}
crate::ffi::pfvar::PF_INET6 => {
Ipv6Addr::from(unsafe { host.addr.pfa._v6addr.__u6_addr.__u6_addr8 }).into()
}
_ => return Err(Error::from(ErrorInternal::InvalidAddressFamily(family))),
};
let port = u16::from_be(unsafe { host.xport.port });
Ok(SocketAddr::new(ip, port))
}
#[cfg(test)]
mod tests {
use super::pfsync_state_host;
use crate::{AddrFamily, state::parse_address};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
#[test]
fn test_parse_ipv4_address() {
const EXPECTED_IP: Ipv4Addr = Ipv4Addr::new(1, 2, 3, 4);
const EXPECTED_PORT: u16 = 12345;
let mut host: pfsync_state_host = unsafe { std::mem::zeroed() };
host.addr.pfa._v4addr.s_addr = u32::from_be_bytes(EXPECTED_IP.octets()).to_be();
host.xport.port = EXPECTED_PORT.to_be();
let family = u8::from(AddrFamily::Ipv4);
let address = unsafe { parse_address(family, host) }.unwrap();
assert_eq!(address, SocketAddr::new(EXPECTED_IP.into(), EXPECTED_PORT));
}
#[test]
fn test_parse_ipv6_address() {
const EXPECTED_IP: Ipv6Addr = Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 0x7f);
const EXPECTED_PORT: u16 = 12345;
let mut host: pfsync_state_host = unsafe { std::mem::zeroed() };
host.addr.pfa._v6addr.__u6_addr.__u6_addr8 = EXPECTED_IP.octets();
host.xport.port = EXPECTED_PORT.to_be();
let family = u8::from(AddrFamily::Ipv6);
let address = unsafe { parse_address(family, host) }.unwrap();
assert_eq!(address, SocketAddr::new(EXPECTED_IP.into(), EXPECTED_PORT));
}
}