//! WinTUN driver extraction and management //! //! Extracts wintun.dll from embedded resources and installs the TUN adapter. use std::path::PathBuf; use anyhow::{Context, Result}; use std::fs; /// Embedded wintun.dll (x64) - placeholder, actual DLL is in resources const WINTUN_DLL: &[u8] = include_bytes!("../resources/wintun.dll"); /// WinTUN adapter GUID (consistent across installs) #[allow(dead_code)] const ADAPTER_GUID: &str = "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"; /// TUN adapter name #[allow(dead_code)] const ADAPTER_NAME: &str = "ostp TUN"; /// Extract wintun.dll to installation directory pub async fn extract_driver(install_path: &PathBuf) -> Result<()> { let dll_path = install_path.join("wintun.dll"); // Create directory if needed fs::create_dir_all(install_path) .context("Failed to create installation directory")?; // Check if already exists with correct version if dll_path.exists() { let existing = fs::read(&dll_path)?; if existing == WINTUN_DLL { return Ok(()); // Already up to date } } // Write the DLL fs::write(&dll_path, WINTUN_DLL) .context("Failed to write wintun.dll")?; Ok(()) } /// Create the TUN adapter using wintun API #[allow(dead_code)] pub async fn create_adapter(install_path: &PathBuf) -> Result<()> { // Load wintun.dll dynamically let dll_path = install_path.join("wintun.dll"); if !dll_path.exists() { anyhow::bail!("wintun.dll not found at {:?}", dll_path); } // Use libloading to call WintunCreateAdapter // This is a simplified version - full implementation would use the wintun crate #[cfg(windows)] { use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; // Convert strings to wide strings for Windows API let _adapter_name: Vec = OsStr::new(ADAPTER_NAME) .encode_wide() .chain(std::iter::once(0)) .collect(); let _tunnel_type: Vec = OsStr::new("Ospab") .encode_wide() .chain(std::iter::once(0)) .collect(); // Parse GUID let _guid = parse_guid(ADAPTER_GUID)?; // In production, we'd call: // WintunCreateAdapter(adapter_name, tunnel_type, &guid) // For now, we'll use the wintun crate when it's integrated tracing::info!("TUN adapter creation would happen here"); } Ok(()) } /// Delete the TUN adapter pub async fn delete_adapter() -> Result<()> { #[cfg(windows)] { // WintunDeleteAdapter would be called here tracing::info!("TUN adapter deletion would happen here"); } Ok(()) } /// Remove wintun driver files pub async fn remove_driver() -> Result<()> { // Delete adapter first delete_adapter().await?; // Find and remove DLL from common locations let paths = [ PathBuf::from(r"C:\Program Files\Ospab Network\OSTP\wintun.dll"), ]; for path in &paths { if path.exists() { fs::remove_file(path).ok(); } } Ok(()) } /// Check if wintun is installed and working pub fn is_installed() -> bool { let system_dll = PathBuf::from(r"C:\Program Files\Ospab Network\OSTP\wintun.dll"); system_dll.exists() } /// Get wintun version from DLL #[allow(dead_code)] pub fn get_version() -> Option { // Would extract version info from PE header // For now, return embedded version Some("0.14.1".to_string()) } /// Parse a GUID string into bytes #[cfg(windows)] #[allow(dead_code)] fn parse_guid(s: &str) -> Result<[u8; 16]> { let s = s.trim_matches(|c| c == '{' || c == '}'); let parts: Vec<&str> = s.split('-').collect(); if parts.len() != 5 { anyhow::bail!("Invalid GUID format"); } let mut guid = [0u8; 16]; // Parse each part let d1 = u32::from_str_radix(parts[0], 16)?; let d2 = u16::from_str_radix(parts[1], 16)?; let d3 = u16::from_str_radix(parts[2], 16)?; let d4 = u16::from_str_radix(parts[3], 16)?; let d5 = u64::from_str_radix(parts[4], 16)?; guid[0..4].copy_from_slice(&d1.to_le_bytes()); guid[4..6].copy_from_slice(&d2.to_le_bytes()); guid[6..8].copy_from_slice(&d3.to_le_bytes()); guid[8..10].copy_from_slice(&d4.to_be_bytes()); guid[10..16].copy_from_slice(&d5.to_be_bytes()[2..8]); Ok(guid) } #[cfg(test)] mod tests { use super::*; #[test] #[cfg(windows)] fn test_parse_guid() { let guid = parse_guid(ADAPTER_GUID).unwrap(); assert_eq!(guid.len(), 16); } }