Skip to content

Commit

Permalink
fixup: improve safety docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dlon committed Jul 24, 2024
1 parent a0cb0be commit 4937441
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 22 deletions.
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,12 @@ impl PfCtl {
let wrapped_states = self
.get_states_inner()?
.into_iter()
.map(State::new)
.map(|state| {
// SAFETY: `DIOCGETSTATE` calls `pf_state_export`, where `pfsync_state` is zero-initialized.
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/pf_ioctl.c#L1247
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/pf_ioctl.c#L3583
unsafe { State::new(state) }
})
.collect();
Ok(wrapped_states)
}
Expand Down
38 changes: 17 additions & 21 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};

use crate::ffi::pfvar::pfsync_state_host;
use crate::{ffi::pfvar::pfsync_state, Direction, Proto};
use crate::{AddrFamily, Error, ErrorInternal, Result};
use crate::{Error, ErrorInternal, Result};

/// PF connection state created by a stateful rule
#[derive(Clone)]
Expand All @@ -24,7 +24,15 @@ impl fmt::Debug for State {
}

impl State {
pub(crate) fn new(sync_state: pfsync_state) -> State {
/// Wrap `pfsync_state` so that it can be accessed safely.
///
/// # Safety
///
/// `sync_state.lan` and `sync_state.ext_lan` must set an address and port:
/// * If `sync_state.af_lan == PF_INET`, then `host.addr.pfa._v4addr` must be initialized.
/// * If `sync_state.af_lan == PF_INET6`, then `host.addr.pfa._v6addr` must be initialized.
/// * `host.xport.port` must be initialized.
pub(crate) unsafe fn new(sync_state: pfsync_state) -> State {
State { sync_state }
}

Expand All @@ -40,23 +48,13 @@ impl State {

/// Return the local socket address for this state
pub fn local_address(&self) -> Result<SocketAddr> {
// SAFETY: `pf_state_export` sets all fields. The port is zero-initialized if the transport
// protocol does not contain ports.
//
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/pf_ioctl.c#L1247
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/pf.c#L4474

// SAFETY: The address and port are initialized according to the contract of `Self::new`.
unsafe { parse_address(self.sync_state.af_lan, self.sync_state.lan) }
}

/// Return the remote socket address for this state
pub fn remote_address(&self) -> Result<SocketAddr> {
// SAFETY: `pf_state_export` sets all fields. The port is zero-initialized if the transport
// protocol does not contain ports.
//
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/pf_ioctl.c#L1247
// https://github.com/apple-oss-distributions/xnu/blob/main/bsd/net/pf.c#L4474

// SAFETY: The address and port are initialized according to the contract of `Self::new`.
unsafe { parse_address(self.sync_state.af_lan, self.sync_state.ext_lan) }
}

Expand All @@ -71,18 +69,16 @@ impl State {
/// # Safety
///
/// `host` must contain a valid address and a port:
/// * If `AddrFamily::try_from(family) == Ok(AddrFamily::Ipv4)`, then `host.addr.pfa._v4addr` must
/// be set.
/// * If `AddrFamily::try_from(family) == Ok(AddrFamily::Ipv6)`, then `host.addr.pfa._v6addr` must
/// be set.
/// * If `family == PF_INET`, then `host.addr.pfa._v4addr` must be initialized.
/// * If `family == PF_INET6`, then `host.addr.pfa._v6addr` must be initialized.
/// * `host.xport.port` must always be initialized.
unsafe fn parse_address(family: u8, host: pfsync_state_host) -> Result<SocketAddr> {
let ip = match AddrFamily::try_from(family) {
Ok(AddrFamily::Ipv4) => {
let ip = match u32::from(family) {
crate::ffi::pfvar::PF_INET => {
// SAFETY: The caller has initialized this memory
Ipv4Addr::from(u32::from_be(unsafe { host.addr.pfa._v4addr.s_addr })).into()
}
Ok(AddrFamily::Ipv6) => {
crate::ffi::pfvar::PF_INET6 => {
// SAFETY: The caller has initialized this memory
Ipv6Addr::from(unsafe { host.addr.pfa._v6addr.__u6_addr.__u6_addr8 }).into()
}
Expand Down

0 comments on commit 4937441

Please sign in to comment.