pub fn create(cfg: TunConfig) -> Result<Self, TunError> {
        // 1. create a new tun device by opening the special device `/dev/tun`
        let tun_dev_path = CStr::from_bytes_with_nul(TUN_DEVICE_PATH.as_ref())
            .map_err(|_| TunError::InvalidCString)?;

        // SAFETY: tun_dev_path is validated above as a CStr, ensuring it
        // has exactly one null byte at the end of the string
        let fd = unsafe { libc::open(tun_dev_path.as_ptr(), libc::O_RDWR) };
        if fd == -1 {
            return Err(TunError::IO(io::Error::last_os_error()));
        }

        // 2. set the device to broadcast mode (vs. point to point) w/ multicast
        let flags: i32 = libc::IFF_BROADCAST | libc::IFF_MULTICAST;

        // SAFETY: ioctl has been verified using truss to be correct
        if unsafe { libc::ioctl(fd, TUNSIFMODE, &flags as *const i32) } == -1 {
            tracing::error!("failed to set interface to broadcast mode");
            return Err(TunError::Generic(Box::new(nix::errno::Errno::last())));
        }

        // 3. get the device name
        // fdevname() seems to be missing from the libc crate so we'll go the
        // fstat route with devname_r()

        let mut statbuf = MaybeUninit::<libc::stat>::zeroed();

        // SAFTEY: fd is guarenteed to be valid & statbuf is zerod
        if unsafe { libc::fstat(fd, statbuf.as_mut_ptr()) } == -1 {
            return Err(TunError::IO(io::Error::last_os_error()));
        }

        // SAFETY: fstat() error code has been checked and is guarenteed
        // to be success at this point, assume buffer is initialized
        let statbuf = unsafe { statbuf.assume_init() };

        let mut name = [0u8; libc::IFNAMSIZ];

        // SAFETY: buffer is guarenteed to be large enough to hold the name
        // of the returned interface (IFNAMSIZ)
        if unsafe {
            libc::devname_r(
                statbuf.st_rdev,
                libc::S_IFCHR,
                name.as_mut_ptr() as *mut i8,
                name.len() as i32,
            )
        } == ptr::null_mut()
        {
            return Err(TunError::IO(io::Error::last_os_error()));
        }

        // 4. create socket file descriptor used to configure interface
        //(via socket ioctls)
        // SAFETY: socket call uses standard parameters and return value is checked
        let sock_fd = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
        if sock_fd == -1 {
            return Err(TunError::DeviceNotFound);
        }

        // 4. create OsTun instance
        let mut tun = Self {
            fd,
            sock_fd,
            name,
            packet_info: cfg.packet_info,
        };

        // 5. configure device
        tun.configure(cfg)?;

        Ok(tun)
    }
/// Creates a new TUN device on the OS
///
/// # Privileges
/// Requires root (or superuser) privileges to allocate a TUN device
///
/// # Arguments
/// * `cfg` - tun configuration options
Creates a new TUN device on the OS
Creates a new TUN device on the OS
pub fn create(cfg: TunConfig) -> Result<Self, TunError> {
        // 1. create a new tun device by opening the special device `/dev/tun`
        let tun_dev_path = CStr::from_bytes_with_nul(TUN_DEVICE_PATH.as_ref())
            .map_err(|_| TunError::InvalidCString)?;
        // SAFETY: tun_dev_path is validated above as a CStr, ensuring it
        // has exactly one null byte at the end of the string
        let fd = unsafe { libc::open(tun_dev_path.as_ptr(), libc::O_RDWR) };
        if fd == -1 {
            return Err(TunError::IO(io::Error::last_os_error()));
        }
        // 2. set the device to broadcast mode (vs. point to point) w/ multicast
        let flags: i32 = libc::IFF_BROADCAST | libc::IFF_MULTICAST;
        // SAFETY: ioctl has been verified using truss to be correct
        if unsafe { libc::ioctl(fd, TUNSIFMODE, &flags as *const i32) } == -1 {
            tracing::error!("failed to set interface to broadcast mode");
            return Err(TunError::Generic(Box::new(nix::errno::Errno::last())));
        }
        // 3. get the device name
        // fdevname() seems to be missing from the libc crate so we'll go the
        // fstat route with devname_r()
        let mut statbuf = MaybeUninit::<libc::stat>::zeroed();
        // SAFTEY: fd is guarenteed to be valid & statbuf is zerod
        if unsafe { libc::fstat(fd, statbuf.as_mut_ptr()) } == -1 {
            return Err(TunError::IO(io::Error::last_os_error()));
        }
        // SAFETY: fstat() error code has been checked and is guarenteed
        // to be success at this point, assume buffer is initialized
        let statbuf = unsafe { statbuf.assume_init() };
        let mut name = [0u8; libc::IFNAMSIZ];
        // SAFETY: buffer is guarenteed to be large enough to hold the name
        // of the returned interface (IFNAMSIZ)
        if unsafe {
            libc::devname_r(
                statbuf.st_rdev,
                libc::S_IFCHR,
                name.as_mut_ptr() as *mut i8,
                name.len() as i32,
            )
        } == ptr::null_mut()
        {
            return Err(TunError::IO(io::Error::last_os_error()));
        }
        // 4. create socket file descriptor used to configure interface
        //(via socket ioctls)
        // SAFETY: socket call uses standard parameters and return value is checked
        let sock_fd = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
        if sock_fd == -1 {
            return Err(TunError::DeviceNotFound);
        }
        // 4. create OsTun instance
        let mut tun = Self {
            fd,
            sock_fd,
            name,
            packet_info: cfg.packet_info,
        };
        // 5. configure device
        tun.configure(cfg)?;
        Ok(tun)
    }
pub fn create ( cfg : TunConfig ) -> Result < Self , TunError > { // 1. create a new tun device by opening the special device `/dev/tun` let tun_dev_path = CStr :: from_bytes_with_nul ( TUN_DEVICE_PATH . as_ref ( ) ) . map_err ( | _ | TunError :: InvalidCString ) ? ; // SAFETY: tun_dev_path is validated above as a CStr, ensuring it // has exactly one null byte at the end of the string let fd = unsafe { libc :: open ( tun_dev_path . as_ptr ( ) , libc :: O_RDWR ) } ; if fd == - 1 { return Err ( TunError :: IO ( io :: Error :: last_os_error ( ) ) ) ; } // 2. set the device to broadcast mode (vs. point to point) w/ multicast let flags : i32 = libc :: IFF_BROADCAST | libc :: IFF_MULTICAST ; // SAFETY: ioctl has been verified using truss to be correct if unsafe { libc :: ioctl ( fd , TUNSIFMODE , & flags as * const i32 ) } == - 1 { tracing :: error ! ( " " ) ; return Err ( TunError :: Generic ( Box :: new ( nix :: errno :: Errno :: last ( ) ) ) ) ; } // 3. get the device name // fdevname() seems to be missing from the libc crate so we'll go the // fstat route with devname_r() let mut statbuf = MaybeUninit :: < libc :: stat > :: zeroed ( ) ; // SAFTEY: fd is guarenteed to be valid & statbuf is zerod if unsafe { libc :: fstat ( fd , statbuf . as_mut_ptr ( ) ) } == - 1 { return Err ( TunError :: IO ( io :: Error :: last_os_error ( ) ) ) ; } // SAFETY: fstat() error code has been checked and is guarenteed // to be success at this point, assume buffer is initialized let statbuf = unsafe { statbuf . assume_init ( ) } ; let mut name = [ 0u8 ; libc :: IFNAMSIZ ] ; // SAFETY: buffer is guarenteed to be large enough to hold the name // of the returned interface (IFNAMSIZ) if unsafe { libc :: devname_r ( statbuf . st_rdev , libc :: S_IFCHR , name . as_mut_ptr ( ) as * mut i8 , name . len ( ) as i32 , ) } == ptr :: null_mut ( ) { return Err ( TunError :: IO ( io :: Error :: last_os_error ( ) ) ) ; } // 4. create socket file descriptor used to configure interface //(via socket ioctls) // SAFETY: socket call uses standard parameters and return value is checked let sock_fd = unsafe { libc :: socket ( libc :: AF_INET , libc :: SOCK_DGRAM , 0 ) } ; if sock_fd == - 1 { return Err ( TunError :: DeviceNotFound ) ; } // 4. create OsTun instance let mut tun = Self { fd , sock_fd , name , packet_info : cfg . packet_info , } ; // 5. configure device tun . configure ( cfg ) ? ; Ok ( tun ) }
Creates a new TUN device on the OS
Creates a new TUN device on the OS
cfg
TunConfig
cfg
TunConfig
privileges
Requires root (or superuser) privileges to allocate a TUN device
Requires root ( or superuser ) privileges to allocate a TUN device