tunio 0.3.0

Crate for creating and managing TUN/TAP interfaces with async support. Works best with netconfig crate.
Documentation
use crate::Error;
use io_lifetimes::OwnedFd;
use libc::{PF_SYSTEM, SYSPROTO_CONTROL};
use nix::sys::socket::SysControlAddr;
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use std::mem;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};

const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";

pub(crate) fn create_device(name: &str) -> Result<OwnedFd, Error> {
    let mut id = match name {
        s if s.starts_with("utun") => s[4..].parse().map_err(|_| Error::InterfaceNameInvalid),
        _ => Err(Error::InterfaceNameInvalid),
    }?;
    id += 1;

    let tun_device = Socket::new(
        Domain::from(PF_SYSTEM),
        Type::DGRAM,
        Some(Protocol::from(SYSPROTO_CONTROL)),
    )
    .unwrap();

    let sa = SysControlAddr::from_name(tun_device.as_raw_fd(), UTUN_CONTROL_NAME, id).unwrap();

    let (_, sa) = unsafe {
        SockAddr::init(|sa_storage, len| {
            let sockaddr = sa_storage as *mut libc::sockaddr_ctl;
            *sockaddr = *sa.as_ref();
            *len = mem::size_of::<libc::sockaddr_ctl>() as _;
            Ok(())
        })
    }
    .unwrap();
    tun_device.connect(&sa).unwrap();

    Ok(unsafe { OwnedFd::from_raw_fd(tun_device.into_raw_fd()) })
}