wiretun 0.5.0

WireGuard Library
Documentation
use std::ffi::CStr;
use std::os::fd::RawFd;
use std::{io, mem, ptr};

use libc::*;
use nix::fcntl::{fcntl, FcntlArg, OFlag};
use nix::{ioctl_read_bad, ioctl_write_ptr_bad};

use crate::tun::Error;

pub const SIOCSIFMTU: u64 = 0x80206934;
pub const SIOCGIFMTU: u64 = 0xc0206933;
ioctl_read_bad!(ioctl_get_mtu, SIOCGIFMTU, ifreq);
ioctl_write_ptr_bad!(ioctl_set_mtu, SIOCSIFMTU, ifreq);

pub const CTRL_NAME: [c_char; MAX_KCTL_NAME] = [
    b'c' as _, b'o' as _, b'm' as _, b'.' as _, b'a' as _, b'p' as _, b'p' as _, b'l' as _,
    b'e' as _, b'.' as _, b'n' as _, b'e' as _, b't' as _, b'.' as _, b'u' as _, b't' as _,
    b'u' as _, b'n' as _, b'_' as _, b'c' as _, b'o' as _, b'n' as _, b't' as _, b'r' as _,
    b'o' as _, b'l' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
    b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _, b'\0' as _,
];

#[repr(C)]
#[derive(Copy, Clone)]
pub union ifrn {
    pub name: [c_char; IFNAMSIZ],
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifdevmtu {
    pub current: c_int,
    pub min: c_int,
    pub max: c_int,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub union ifku {
    pub ptr: *mut c_void,
    pub value: c_int,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub union ifru {
    pub addr: sockaddr,
    pub dstaddr: sockaddr,
    pub broadaddr: sockaddr,

    pub flags: c_short,
    pub metric: c_int,
    pub mtu: c_int,
    pub phys: c_int,
    pub media: c_int,
    pub intval: c_int,
    pub data: *mut c_void,
    pub devmtu: ifdevmtu,
    pub wake_flags: c_uint,
    pub route_refcnt: c_uint,
    pub cap: [c_int; 2],
    pub functional_type: c_uint,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ifreq {
    pub ifrn: ifrn,
    pub ifru: ifru,
}

impl ifreq {
    pub fn new(name: &str) -> Self {
        let mut me: Self = unsafe { mem::zeroed() };
        unsafe {
            ptr::copy_nonoverlapping(
                name.as_ptr() as *const libc::c_char,
                me.ifrn.name.as_mut_ptr(),
                name.len(),
            )
        }
        me
    }
}

pub fn set_nonblocking(fd: RawFd) -> Result<(), Error> {
    let flag = fcntl(fd, FcntlArg::F_GETFL)
        .map(OFlag::from_bits_retain)
        .map_err(Error::Sys)?;
    let flag = OFlag::O_NONBLOCK | flag;
    fcntl(fd, FcntlArg::F_SETFL(flag)).map_err(Error::Sys)?;
    Ok(())
}

pub unsafe fn get_iface_name(fd: RawFd) -> Result<String, io::Error> {
    const MAX_LEN: usize = 256;
    let mut name = [0u8; MAX_LEN];
    let mut name_len: libc::socklen_t = name.len() as _;
    if libc::getsockopt(
        fd,
        libc::SYSPROTO_CONTROL,
        libc::UTUN_OPT_IFNAME,
        name.as_mut_ptr() as _,
        &mut name_len,
    ) < 0
    {
        return Err(io::Error::last_os_error());
    }
    Ok(CStr::from_ptr(name.as_ptr() as *const libc::c_char)
        .to_string_lossy()
        .into())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_ctrl_name() {
        let expected = {
            const CTRL_NAME_IN_BYTES: &[u8] = b"com.apple.net.utun_control";
            let mut name: [c_char; libc::MAX_KCTL_NAME] = [0_i8; libc::MAX_KCTL_NAME];
            name[..CTRL_NAME_IN_BYTES.len()].copy_from_slice(
                CTRL_NAME_IN_BYTES
                    .iter()
                    .map(|&x| x as _)
                    .collect::<Vec<_>>()
                    .as_slice(),
            );
            name
        };

        assert_eq!(CTRL_NAME, expected);
    }
}