libtun 0.1.0

a cross-platform(macosx, linux) tunnel library
Documentation
use super::run_shell;
use crate::errors::*;
use ipnet::IpNet;
use libc::c_int;
use std::fs::File;
use std::io::{Error, ErrorKind};

extern "C" {
    #[link_name = "utun_open"]
    fn utun_open(fd: *mut c_int, idx: c_int) -> c_int;
}

pub struct RawTun {
    name: String,
    reader: Option<File>,
    writer: Option<File>,
}

impl RawTun {
    pub async fn new() -> Result<RawTun> {
        let mut fd: c_int = 0;
        for tun_idx in 1..1024 {
            let status = unsafe { utun_open(&mut fd, tun_idx) };
            match status {
                0 => {
                    let f2: std::fs::File = unsafe { std::os::unix::io::FromRawFd::from_raw_fd(fd) };
                    let name = format!("utun{}", tun_idx);
                    // let read_fd = fd.try_clone().context(CreateTun)?;
                    let write_fd = f2.try_clone().context(CreateTun)?;
                    return Ok(RawTun {
                        name,
                        reader: Some(f2),
                        writer: Some(write_fd),
                    });
                }
                16 => { /* Resource Busy, try next */ }
                _ => Err(Error::from_raw_os_error(status)).context(CreateTun)?,
            }
        }
        Err(Error::new(ErrorKind::AddrNotAvailable, "can't open tunnel")).context(CreateTun)?
    }

    pub fn init(&self, addr: &IpNet, mtu: u32) -> Result<()> {
        run_shell(format!(
            "ifconfig {} {} {} mtu {} netmask {} up",
            &self.name,
            addr.addr(),
            addr.addr(),
            mtu,
            addr.netmask(),
        ))?;
        run_shell(format!(
            "route add -net {} -interface {}",
            &addr.network(),
            &self.name
        ))?;
        Ok(())
    }

    pub fn take_reader(&mut self) -> Option<File> {
        self.reader.take()
    }

    pub fn take_writer(&mut self) -> Option<File> {
        self.writer.take()
    }
}