vmnet 0.10.0

Apple's vmnet.framework bindings
Documentation
use crate::error;
use crate::ffi::xpc::XpcObjectT;
use bitflags::bitflags;
use dispatch2::DispatchQueue;
use libc::{in6_addr, in_addr, iovec, size_t};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::ffi::c_void;
use std::os::raw::{c_char, c_int};

pub type NetworkConfigurationRef = *mut c_void;
pub type NetworkRef = *mut c_void;
pub type InterfaceRef = *mut c_void;
pub type InterfaceEventT = u32;
pub type VmnetReturnT = u32;

#[repr(C)]
#[derive(Debug)]
pub struct vmpktdesc {
    pub vm_pkt_size: size_t,
    pub vm_pkt_iov: *mut iovec,
    pub vm_pkt_iovcnt: u32,
    pub vm_flags: u32,
}

// SAFETY: The descriptor's numbers and pointer value can be read concurrently,
// while accessing memory through vm_pkt_iov requires unsafe code.
unsafe impl Sync for vmpktdesc {}

#[link(name = "vmnet", kind = "framework")]
extern "C" {
    // Network configuration functions
    pub fn vmnet_network_configuration_create(
        mode: u32,
        status: *mut VmnetReturnT,
    ) -> NetworkConfigurationRef;
    pub fn vmnet_network_configuration_set_external_interface(
        config: NetworkConfigurationRef,
        interface_name: *const c_char,
    ) -> VmnetReturnT;
    pub fn vmnet_network_configuration_disable_nat44(config: NetworkConfigurationRef);
    pub fn vmnet_network_configuration_disable_nat66(config: NetworkConfigurationRef);
    pub fn vmnet_network_configuration_disable_dhcp(config: NetworkConfigurationRef);
    pub fn vmnet_network_configuration_disable_dns_proxy(config: NetworkConfigurationRef);
    pub fn vmnet_network_configuration_disable_router_advertisement(
        config: NetworkConfigurationRef,
    );
    pub fn vmnet_network_configuration_set_ipv4_subnet(
        config: NetworkConfigurationRef,
        subnet_addr: *const in_addr,
        subnet_mask: *const in_addr,
    ) -> VmnetReturnT;
    pub fn vmnet_network_configuration_set_ipv6_prefix(
        config: NetworkConfigurationRef,
        prefix: *const in6_addr,
        len: u8,
    ) -> VmnetReturnT;
    pub fn vmnet_network_configuration_set_mtu(
        config: NetworkConfigurationRef,
        mtu: u32,
    ) -> VmnetReturnT;
    // Darwin's ether_addr_t contains only unsigned char octet[6], with alignment
    // one and no padding, so a pointer to [u8; 6] has the same pointee layout.
    pub fn vmnet_network_configuration_add_dhcp_reservation(
        config: NetworkConfigurationRef,
        client: *const [u8; 6],
        reservation: *const in_addr,
    ) -> VmnetReturnT;
    // internal_port comes before external_port here, unlike in
    // vmnet_interface_add_ip_port_forwarding_rule
    pub fn vmnet_network_configuration_add_port_forwarding_rule(
        config: NetworkConfigurationRef,
        protocol: u8,
        address_family: u8,
        internal_port: u16,
        external_port: u16,
        internal_address: *const c_void,
    ) -> VmnetReturnT;

    // Network functions
    pub fn vmnet_network_create(
        configuration: NetworkConfigurationRef,
        status: *mut VmnetReturnT,
    ) -> NetworkRef;
    pub fn vmnet_network_get_ipv4_subnet(
        network: NetworkRef,
        subnet: *mut in_addr,
        mask: *mut in_addr,
    );
    pub fn vmnet_network_get_ipv6_prefix(
        network: NetworkRef,
        prefix: *mut in6_addr,
        prefix_len: *mut u8,
    );

    // Interface functions
    pub fn vmnet_start_interface(
        interface_desc: XpcObjectT,
        queue: &DispatchQueue,
        handler: *mut c_void,
    ) -> InterfaceRef;
    pub fn vmnet_interface_start_with_network(
        network: NetworkRef,
        interface_desc: XpcObjectT,
        queue: &DispatchQueue,
        start_block: *mut c_void,
    ) -> InterfaceRef;
    pub fn vmnet_interface_set_event_callback(
        interface: InterfaceRef,
        event_mask: InterfaceEventT,
        queue: Option<&DispatchQueue>,
        callback: *mut c_void,
    ) -> VmnetReturnT;
    pub fn vmnet_read(
        interface: InterfaceRef,
        packets: *mut vmpktdesc,
        pktcnt: *mut c_int,
    ) -> VmnetReturnT;
    pub fn vmnet_write(
        interface: InterfaceRef,
        packets: *mut vmpktdesc,
        pktcnt: *mut c_int,
    ) -> VmnetReturnT;
    pub fn vmnet_stop_interface(
        interface: InterfaceRef,
        queue: &DispatchQueue,
        handler: *mut c_void,
    ) -> VmnetReturnT;

    // Interface port forwarding functions
    pub fn vmnet_interface_add_ip_port_forwarding_rule(
        interface: InterfaceRef,
        protocol: u8,
        external_port: u16,
        address_family: u8,
        internal_address: *const c_void,
        internal_port: u16,
        handler: *mut c_void,
    ) -> VmnetReturnT;
    pub fn vmnet_interface_get_ip_port_forwarding_rules(
        interface: InterfaceRef,
        address_family: u8,
        handler: *mut c_void,
    ) -> VmnetReturnT;
    pub fn vmnet_ip_port_forwarding_rule_get_details(
        rule: XpcObjectT,
        protocol: *mut u8,
        external_port: *mut u16,
        address_family: u8,
        internal_address: *mut c_void,
        internal_port: *mut u16,
    ) -> VmnetReturnT;
    pub fn vmnet_interface_remove_ip_port_forwarding_rule(
        interface: InterfaceRef,
        protocol: u8,
        external_port: u16,
        address_family: u8,
        handler: *mut c_void,
    ) -> VmnetReturnT;

    // Utility functions
    pub fn vmnet_copy_shared_interface_list() -> XpcObjectT;

    // Mode selector
    pub static vmnet_operation_mode_key: *const c_char;

    // Generic options and parameters
    pub static vmnet_mac_address_key: *const c_char;
    pub static vmnet_allocate_mac_address_key: *const c_char;
    pub static vmnet_interface_id_key: *const c_char;
    pub static vmnet_max_packet_size_key: *const c_char;
    pub static vmnet_read_max_packets_key: *const c_char;
    pub static vmnet_write_max_packets_key: *const c_char;
    pub static vmnet_enable_checksum_offload_key: *const c_char;
    pub static vmnet_enable_isolation_key: *const c_char;
    pub static vmnet_enable_tso_key: *const c_char;

    // Host mode
    pub static vmnet_network_identifier_key: *const c_char;
    pub static vmnet_host_ip_address_key: *const c_char;
    pub static vmnet_host_ipv6_address_key: *const c_char;
    pub static vmnet_host_subnet_mask_key: *const c_char;

    // Bridged mode
    pub static vmnet_shared_interface_name_key: *const c_char;

    // Shared and host modes
    pub static vmnet_start_address_key: *const c_char;
    pub static vmnet_end_address_key: *const c_char;
    pub static vmnet_subnet_mask_key: *const c_char;
    pub static vmnet_mtu_key: *const c_char;

    // Shared mode
    pub static vmnet_nat66_prefix_key: *const c_char;

    // Event callback
    pub static vmnet_estimated_packets_available_key: *const c_char;
}

/// A status returned by the [vmnet.framework](https://developer.apple.com/documentation/vmnet).
#[derive(TryFromPrimitive)]
#[repr(u32)]
#[derive(Debug, Eq, PartialEq)]
pub enum Status {
    Success = 1000,
    Failure = 1001,
    MemFailure = 1002,
    InvalidArgument = 1003,
    SetupIncomplete = 1004,
    InvalidAccess = 1005,
    PacketTooBig = 1006,
    BufferExhausted = 1007,
    TooManyPackets = 1008,
    SharingServiceBusy = 1009,
    NotAuthorized = 1010,
}

impl Status {
    pub fn from_ffi(status: u32) -> Result<(), error::Error> {
        let status =
            Status::try_from(status).map_err(|_x| error::Error::VmnetUnknownStatus(status))?;

        match status {
            Status::Success => Ok(()),
            _ => Err(error::Error::VmnetErrorStatus(status)),
        }
    }
}

#[repr(u64)]
#[derive(IntoPrimitive)]
pub enum Mode {
    Host = 1000,
    Shared = 1001,
    Bridged = 1002,
}

bitflags! {
    /// Describes events received for a given [interface callback call](crate::Interface::set_event_callback).
    pub struct Events: u32 {
        const PACKETS_AVAILABLE = 1 << 0;
    }
}