From e854f1f2a11a03c48a1a7d93d0e5c8d56b30bc58 Mon Sep 17 00:00:00 2001 From: shellrow Date: Wed, 23 Apr 2025 00:45:04 +0900 Subject: [PATCH] Update dependencies --- Cargo.toml | 9 +- deps/nex-npcap-helper/Cargo.toml | 35 -- deps/nex-npcap-helper/examples/setup.rs | 136 ----- deps/nex-npcap-helper/src/lib.rs | 31 -- deps/nex-npcap-helper/src/unix/mod.rs | 1 - deps/nex-npcap-helper/src/windows/app.rs | 7 - deps/nex-npcap-helper/src/windows/http.rs | 52 -- deps/nex-npcap-helper/src/windows/mod.rs | 6 - deps/nex-npcap-helper/src/windows/npcap.rs | 265 --------- deps/nex-npcap-helper/src/windows/sys.rs | 162 ------ examples/arp.rs | 2 +- examples/icmp_ping.rs | 6 +- examples/list_interfaces.rs | 23 +- examples/ndp.rs | 2 +- examples/tcp_ping.rs | 12 +- examples/tls_stream.rs | 62 --- examples/udp_ping.rs | 12 +- nex-core/Cargo.toml | 6 +- nex-core/src/ip.rs | 2 +- nex-datalink/Cargo.toml | 10 +- nex-macro-helper/Cargo.toml | 2 +- nex-macro/Cargo.toml | 4 +- nex-packet-builder/Cargo.toml | 4 +- nex-packet/Cargo.toml | 7 +- nex-packet/src/util.rs | 18 - nex-socket/Cargo.toml | 15 +- nex-socket/src/lib.rs | 3 - nex-socket/src/tls/certs.rs | 18 - nex-socket/src/tls/client.rs | 240 --------- nex-socket/src/tls/danger.rs | 83 --- nex-socket/src/tls/mod.rs | 14 - nex-socket/src/tls/server.rs | 150 ------ nex-socket/src/tls/session.rs | 94 ---- nex-socket/src/tls/socket.rs | 595 --------------------- nex-socket/src/tls/state.rs | 49 -- nex-socket/src/tls/stream.rs | 343 ------------ nex-sys/Cargo.toml | 6 +- nex/Cargo.toml | 8 +- 38 files changed, 65 insertions(+), 2429 deletions(-) delete mode 100644 deps/nex-npcap-helper/Cargo.toml delete mode 100644 deps/nex-npcap-helper/examples/setup.rs delete mode 100644 deps/nex-npcap-helper/src/lib.rs delete mode 100644 deps/nex-npcap-helper/src/unix/mod.rs delete mode 100644 deps/nex-npcap-helper/src/windows/app.rs delete mode 100644 deps/nex-npcap-helper/src/windows/http.rs delete mode 100644 deps/nex-npcap-helper/src/windows/mod.rs delete mode 100644 deps/nex-npcap-helper/src/windows/npcap.rs delete mode 100644 deps/nex-npcap-helper/src/windows/sys.rs delete mode 100644 examples/tls_stream.rs delete mode 100644 nex-socket/src/tls/certs.rs delete mode 100644 nex-socket/src/tls/client.rs delete mode 100644 nex-socket/src/tls/danger.rs delete mode 100644 nex-socket/src/tls/mod.rs delete mode 100644 nex-socket/src/tls/server.rs delete mode 100644 nex-socket/src/tls/session.rs delete mode 100644 nex-socket/src/tls/socket.rs delete mode 100644 nex-socket/src/tls/state.rs delete mode 100644 nex-socket/src/tls/stream.rs diff --git a/Cargo.toml b/Cargo.toml index 3443cfc..4400654 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,15 @@ members = [ "nex-sys", "nex-packet-builder" ] -exclude = ["deps/nex-npcap-helper"] [workspace.package] version = "0.18.0" +edition = "2021" authors = ["shellrow "] + +[workspace.dependencies] +serde = { version = "1" } +libc = "0.2" +rand = "0.8" +netdev = { version = "0.34" } +async-io = "2.4" diff --git a/deps/nex-npcap-helper/Cargo.toml b/deps/nex-npcap-helper/Cargo.toml deleted file mode 100644 index 61c04e2..0000000 --- a/deps/nex-npcap-helper/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "nex-npcap-helper" -version = "0.12.0" -edition = "2021" -authors = ["shellrow "] -description = "Helper crate for managing the installation of npcap on Windows, providing essential support for the nex" -repository = "https://github.com/shellrow/nex" -readme = "../../README.md" -keywords = ["network", "windows"] -categories = ["network-programming"] -license = "MIT" - -[dependencies] - -[target.'cfg(windows)'.dependencies] -home = "0.5" -winreg = "0.50" -privilege = "0.3" -sha2 = "0.10" -zip = "0.6" -tokio = { version = "1", optional = true } -futures = { version = "0.3", optional = true } -reqwest = { version = "0.12", features = ["blocking", "rustls-tls", "stream"], optional = true } -indicatif = { version = "0.16", optional = true } - -[target.'cfg(windows)'.dev-dependencies] -inquire = "0.6" - -[features] -download = ["reqwest", "tokio", "futures", "indicatif"] - -[[example]] -name = "setup" -path = "examples/setup.rs" -required-features = ["download"] diff --git a/deps/nex-npcap-helper/examples/setup.rs b/deps/nex-npcap-helper/examples/setup.rs deleted file mode 100644 index e778a4e..0000000 --- a/deps/nex-npcap-helper/examples/setup.rs +++ /dev/null @@ -1,136 +0,0 @@ -use nex_npcap_helper::npcap; -use std::{env, path::PathBuf}; -use inquire::Confirm; - -const USAGE: &str = "Usage: ./setup dst_dir_path: Directory path to download npcap installer and npcap SDK"; - -fn main() { - let dst_dir_path: PathBuf = match env::args().nth(1) { - Some(n) => { - // Check directory path exists - let dst_dir_path = PathBuf::from(n); - if !dst_dir_path.exists() { - panic!("Directory path does not exist"); - } - dst_dir_path - } - None => { - println!("Please provide a directory path to download npcap installer and npcap SDK"); - println!("{}", USAGE); - return; - } - }; - // Check if npcap is installed - if !npcap::npcap_installed() { - let ans: bool = Confirm::new("Npcap is not installed, would you like to install it ?") - .prompt() - .unwrap(); - if ans == false { - println!("Exiting..."); - return; - } - } else { - let ans: bool = Confirm::new("Npcap is already installed. Would you like to reinstall (or update) Npcap ?") - .prompt() - .unwrap(); - if ans == false { - println!("Exiting..."); - return; - } - } - // Download the latest release of npcap installer - let installer_path = match npcap::download_npcap_with_progress(&dst_dir_path) { - Ok(path) => { - println!("Npcap installer downloaded successfully !"); - path - }, - Err(e) => { - println!("{}", e); - return; - }, - }; - // Verify the checksum of the downloaded npcap installer - match npcap::verify_installer_checksum(&installer_path) { - Ok(_) => println!("Npcap installer checksum is correct !"), - Err(e) => { - println!("{}", e); - return; - }, - } - // Install npcap - match npcap::run_npcap_installer(&installer_path) { - Ok(_) => println!("Npcap installed successfully !"), - Err(e) => { - println!("{}", e); - return; - }, - } - // Check if npcap SDK is installed - if !npcap::npcap_sdk_installed() { - let ans: bool = Confirm::new("Npcap SDK is not installed, would you like to install it ?") - .prompt() - .unwrap(); - if ans == false { - println!("Exiting..."); - return; - } - } else { - let ans: bool = Confirm::new("Npcap SDK is already installed. Would you like to reinstall (or update) Npcap SDK ?") - .prompt() - .unwrap(); - if ans == false { - println!("Exiting..."); - return; - } - } - // Download the latest release of npcap sdk - let sdk_path = match npcap::download_npcap_sdk_with_progress(&dst_dir_path) { - Ok(path) => { - println!("Npcap SDK downloaded successfully !"); - path - }, - Err(e) => { - println!("{}", e); - return; - }, - }; - // Verify the checksum of the downloaded npcap sdk - match npcap::verify_sdk_checksum(&sdk_path) { - Ok(_) => println!("Npcap SDK checksum is correct !"), - Err(e) => { - println!("{}", e); - return; - }, - } - // Extract npcap sdk - let sdk_dir = match npcap::extract_npcap_sdk(&sdk_path) { - Ok(dir) => { - println!("Npcap SDK extracted successfully !"); - println!("Npcap SDK extracted to {:?}", dir); - dir - }, - Err(e) => { - println!("{}", e); - return; - }, - }; - // Add npcap SDK to LIB env var - match npcap::add_npcap_sdk_to_lib(sdk_dir) { - Ok(_) => println!("Npcap SDK added to LIB env var successfully !"), - Err(e) => { - println!("{}", e); - return; - }, - } - // Remove downloaded npcap installer and sdk - let ans: bool = Confirm::new("Would you like to remove the downloaded npcap installer and npcap SDK ?") - .prompt() - .unwrap(); - if ans { - println!("Removing downloaded npcap installer and npcap SDK..."); - std::fs::remove_file(&installer_path).unwrap(); - std::fs::remove_file(&sdk_path).unwrap(); - println!("Downloaded npcap installer and npcap SDK removed successfully !"); - } - println!("Npcap setup completed successfully !"); -} diff --git a/deps/nex-npcap-helper/src/lib.rs b/deps/nex-npcap-helper/src/lib.rs deleted file mode 100644 index 5fa5e67..0000000 --- a/deps/nex-npcap-helper/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -#[cfg(not(target_os = "windows"))] -mod unix; -#[cfg(not(target_os = "windows"))] -pub use self::unix::*; - -#[cfg(target_os = "windows")] -mod windows; -#[cfg(target_os = "windows")] -pub use self::windows::*; - -#[cfg(target_os = "windows")] -#[cfg(test)] -mod tests { - use crate::npcap; - #[test] - fn test_check_npcap() { - if npcap::npcap_installed() { - println!("npcap installed"); - } else { - println!("npcap not installed"); - } - } - #[test] - fn test_check_npcap_sdk() { - if npcap::npcap_sdk_installed() { - println!("npcap SDK installed"); - } else { - println!("npcap SDK not installed"); - } - } -} diff --git a/deps/nex-npcap-helper/src/unix/mod.rs b/deps/nex-npcap-helper/src/unix/mod.rs deleted file mode 100644 index 8b13789..0000000 --- a/deps/nex-npcap-helper/src/unix/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/deps/nex-npcap-helper/src/windows/app.rs b/deps/nex-npcap-helper/src/windows/app.rs deleted file mode 100644 index e6624cb..0000000 --- a/deps/nex-npcap-helper/src/windows/app.rs +++ /dev/null @@ -1,7 +0,0 @@ -/// Application information on system -#[derive(Debug, Clone)] -pub struct AppInfo { - pub display_name: String, - pub display_version: String, - pub uninstall_string: String, -} diff --git a/deps/nex-npcap-helper/src/windows/http.rs b/deps/nex-npcap-helper/src/windows/http.rs deleted file mode 100644 index fb5f03b..0000000 --- a/deps/nex-npcap-helper/src/windows/http.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::{error::Error, io::Write, path::PathBuf}; -use futures::stream::StreamExt; - -#[derive(Debug, Clone)] -pub enum DownloadProgress { - ContentLength(u64), - Downloaded(u64), -} - -pub async fn download_file(url: String, save_file_path: PathBuf) -> Result<(), Box> { - // Check and create download dir - let file_path = std::path::Path::new(&save_file_path); - if let Some(parent_dir) = file_path.parent() { - if !parent_dir.exists() { - std::fs::create_dir_all(parent_dir)?; - } - }else{ - return Err("Invalid save file path".into()); - } - // Download file - let response = reqwest::get(&url).await?; - let mut dest = std::fs::File::create(&save_file_path)?; - let content = response.bytes().await?; - dest.write_all(&content)?; - Ok(()) -} - -pub async fn download_file_with_progress(url: String, save_file_path: &PathBuf, progress_tx: tokio::sync::mpsc::Sender) -> Result<(), Box> { - // Check and create download dir - let file_path = std::path::Path::new(&save_file_path); - if let Some(parent_dir) = file_path.parent() { - if !parent_dir.exists() { - std::fs::create_dir_all(parent_dir)?; - } - }else{ - return Err("Invalid save file path".into()); - } - // Download file with progress - let response = reqwest::get(&url).await?; - let content_length = response.content_length().unwrap_or(0); - progress_tx.send(DownloadProgress::ContentLength(content_length)).await?; - let mut dest = std::fs::File::create(&save_file_path)?; - let mut downloaded: u64 = 0; - let mut stream = response.bytes_stream(); - while let Some(chunk) = stream.next().await { - let chunk = chunk?; - downloaded += chunk.len() as u64; - dest.write_all(&chunk)?; - progress_tx.send(DownloadProgress::Downloaded(downloaded)).await?; - } - Ok(()) -} \ No newline at end of file diff --git a/deps/nex-npcap-helper/src/windows/mod.rs b/deps/nex-npcap-helper/src/windows/mod.rs deleted file mode 100644 index 893f487..0000000 --- a/deps/nex-npcap-helper/src/windows/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod app; -pub mod npcap; -mod sys; - -#[cfg(feature = "download")] -pub mod http; diff --git a/deps/nex-npcap-helper/src/windows/npcap.rs b/deps/nex-npcap-helper/src/windows/npcap.rs deleted file mode 100644 index e24337b..0000000 --- a/deps/nex-npcap-helper/src/windows/npcap.rs +++ /dev/null @@ -1,265 +0,0 @@ -use super::sys; -use privilege::runas::Command as RunasCommand; -use sha2::{Digest, Sha256}; -use std::error::Error; -use std::fs::File; -use std::path::PathBuf; - -pub(crate) const NPCAP_SOFTWARE_NAME: &str = "Npcap"; -pub(crate) const NPCAP_INSTALL_DIR_NAME: &str = "npcap"; -pub(crate) const NPCAP_SDK_DIR_NAME: &str = "npcap-sdk-1.13"; -pub const NPCAP_INSTALLER_FILENAME: &str = "npcap-1.79.exe"; -pub const NPCAP_SDK_FILENAME: &str = "npcap-sdk-1.13.zip"; -pub(crate) const NPCAP_INSTALLER_HASH: &str = - "A95577EBBC67FC45B319E2EF3A55F4E9B211FE82ED4CB9D8BE6B1A9E2425CE53"; -pub(crate) const NPCAP_SDK_HASH: &str = - "DAD1F2BF1B02B787BE08CA4862F99E39A876C1F274BAC4AC0CEDC9BBC58F94FD"; -#[allow(dead_code)] -pub(crate) const NPCAP_DIST_BASE_URL: &str = "https://npcap.com/dist/"; -pub(crate) const NPCAP_LIB_NAME: &str = "Packet.lib"; - -/// Check if npcap is installed. -/// This function only check if npcap is installed, not check version. -pub fn npcap_installed() -> bool { - sys::software_installed(NPCAP_SOFTWARE_NAME.to_owned()) -} - -/// Check if npcap SDK is installed. -/// This function only check if npcap SDK is installed, not check version. -pub fn npcap_sdk_installed() -> bool { - let env_lib_value: String = sys::get_env_lib(); - if env_lib_value.is_empty() { - return false; - } - // Split env_lib_value by ; - let lib_path_list: Vec<&str> = env_lib_value.split(";").collect(); - // Check if npcap sdk is in env_lib_value - // Search for Packet.lib - for lib_path in lib_path_list { - let packet_lib_path: String = format!("{}\\{}", lib_path, NPCAP_LIB_NAME); - if std::path::Path::new(&packet_lib_path).exists() { - return true; - } - } - false -} - -#[cfg(feature = "download")] -/// Download npcap installer -pub fn download_npcap(dst_dir_path: String) -> Result<(), Box> { - let npcap_installer_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_INSTALLER_FILENAME); - // Check and create download dir - let dir_path = std::path::Path::new(&dst_dir_path); - if !dir_path.exists() { - std::fs::create_dir_all(dir_path)?; - } - let npcap_target_path: std::path::PathBuf = dir_path.join(NPCAP_INSTALLER_FILENAME); - // Download npcap installer if not exists - if !std::path::Path::new(&npcap_target_path).exists() { - let mut response: reqwest::blocking::Response = - reqwest::blocking::get(&npcap_installer_url)?; - let mut file: File = File::create(&npcap_target_path)?; - response.copy_to(&mut file)?; - } - Ok(()) -} - -#[cfg(feature = "download")] -/// Download npcap installer with progress -pub fn download_npcap_with_progress(dst_dir_path: &PathBuf) -> Result> { - let npcap_installer_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_INSTALLER_FILENAME); - // Check and create download dir - if !dst_dir_path.exists() { - std::fs::create_dir_all(&dst_dir_path)?; - } - let npcap_target_path: std::path::PathBuf = dst_dir_path.join(NPCAP_INSTALLER_FILENAME); - // Download npcap installer if not exists - if std::path::Path::new(&npcap_target_path).exists() { - return Ok(npcap_target_path); - } - let rt = tokio::runtime::Runtime::new().unwrap(); - let installer_save_path: PathBuf = npcap_target_path.clone(); - rt.block_on(async { - // create a channel for progress - let (progress_tx, mut progress_rx) = tokio::sync::mpsc::channel(100); - // spawn a task to handle the progress - tokio::spawn(async move { - let _ = super::http::download_file_with_progress(npcap_installer_url, &installer_save_path, progress_tx).await; - }); - // Display progress with indicatif - let bar = indicatif::ProgressBar::new(1000); - bar.set_style(indicatif::ProgressStyle::default_bar().template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})").progress_chars("#>-")); - while let Some(progress) = progress_rx.recv().await { - match progress { - super::http::DownloadProgress::ContentLength(content_length) => { - println!("Content-Length: {}", content_length); - bar.set_length(content_length); - } - super::http::DownloadProgress::Downloaded(downloaded) => { - bar.set_position(downloaded); - } - } - } - bar.finish(); - }); - Ok(npcap_target_path) -} - -/// Verify npcap installer SHA256 checksum -pub fn verify_installer_checksum(file_path: &PathBuf) -> Result<(), Box> { - let mut file: File = File::open(&file_path)?; - let mut hasher = Sha256::new(); - std::io::copy(&mut file, &mut hasher)?; - let hash_result = hasher.finalize(); - let hash_result: String = format!("{:X}", hash_result); - - if hash_result != NPCAP_INSTALLER_HASH { - return Err(format!("Error: checksum failed... {}", hash_result).into()); - } - Ok(()) -} - -/// Run npcap installer. -/// -/// Warning: This function will run npcap installer with admin privileges. -/// -/// This function only run verified npcap installer. -pub fn run_npcap_installer(file_path: &PathBuf) -> Result<(), Box> { - // Check file exists - if !std::path::Path::new(&file_path).exists() { - return Err("Error: file not found...".into()); - } - // Verify checksum - verify_installer_checksum(file_path)?; - let exit_status: std::process::ExitStatus = RunasCommand::new(&file_path) - .arg("/loopback_support=yes") - .arg("/winpcap_mode=yes") - .run()?; - if !exit_status.success() { - return Err("Error: Npcap installation failed !".into()); - } - Ok(()) -} - -#[cfg(feature = "download")] -/// Download npcap SDK -pub fn download_npcap_sdk(dst_dir_path: String) -> Result<(), Box> { - let npcap_sdk_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_SDK_FILENAME); - // Check and create download dir - let dir_path = std::path::Path::new(&dst_dir_path); - if !dir_path.exists() { - std::fs::create_dir_all(dir_path)?; - } - let npcap_sdk_target_path: std::path::PathBuf = dir_path.join(NPCAP_SDK_FILENAME); - // Download npcap sdk if not exists - if !std::path::Path::new(&npcap_sdk_target_path).exists() { - let mut response: reqwest::blocking::Response = reqwest::blocking::get(&npcap_sdk_url)?; - let mut file: File = File::create(&npcap_sdk_target_path)?; - response.copy_to(&mut file)?; - } - Ok(()) -} - -#[cfg(feature = "download")] -/// Download npcap SDK with progress -pub fn download_npcap_sdk_with_progress(dst_dir_path: &PathBuf) -> Result> { - let npcap_sdk_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_SDK_FILENAME); - // Check and create download dir - if !dst_dir_path.exists() { - std::fs::create_dir_all(&dst_dir_path)?; - } - let npcap_sdk_target_path: std::path::PathBuf = dst_dir_path.join(NPCAP_SDK_FILENAME); - // Download npcap sdk if not exists - if std::path::Path::new(&npcap_sdk_target_path).exists() { - return Ok(npcap_sdk_target_path); - } - let rt = tokio::runtime::Runtime::new().unwrap(); - let sdk_save_path: PathBuf = npcap_sdk_target_path.clone(); - rt.block_on(async { - // create a channel for progress - let (progress_tx, mut progress_rx) = tokio::sync::mpsc::channel(100); - // spawn a task to handle the progress - tokio::spawn(async move { - let _ = super::http::download_file_with_progress(npcap_sdk_url, &sdk_save_path, progress_tx).await; - }); - // Display progress with indicatif - let bar = indicatif::ProgressBar::new(1000); - bar.set_style(indicatif::ProgressStyle::default_bar().template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})").progress_chars("#>-")); - while let Some(progress) = progress_rx.recv().await { - match progress { - super::http::DownloadProgress::ContentLength(content_length) => { - println!("Content-Length: {}", content_length); - bar.set_length(content_length); - } - super::http::DownloadProgress::Downloaded(downloaded) => { - bar.set_position(downloaded); - } - } - } - bar.finish(); - }); - Ok(npcap_sdk_target_path) -} - -/// Verify npcap SDK SHA256 checksum -pub fn verify_sdk_checksum(file_path: &PathBuf) -> Result<(), Box> { - let mut file: File = File::open(&file_path)?; - let mut hasher = Sha256::new(); - std::io::copy(&mut file, &mut hasher)?; - let hash_result = hasher.finalize(); - let hash_result: String = format!("{:X}", hash_result); - - if hash_result != NPCAP_SDK_HASH { - return Err("Error: checksum failed...".into()); - } - Ok(()) -} - -/// Extract npcap SDK -pub fn extract_npcap_sdk(file_path: &PathBuf) -> Result> { - // Check file exists - if !std::path::Path::new(&file_path).exists() { - return Err("Error: file not found...".into()); - } - // Verify checksum - verify_sdk_checksum(file_path)?; - // Extract npcap SDK - let npcap_sdk_extract_dir: String = format!( - "{}\\{}", - sys::get_install_path(NPCAP_INSTALL_DIR_NAME), - NPCAP_SDK_DIR_NAME - ); - let npcap_sdk_extract_dir = std::path::PathBuf::from(npcap_sdk_extract_dir); - let mut archive: zip::ZipArchive = zip::ZipArchive::new(File::open(&file_path)?)?; - for i in 0..archive.len() { - let mut file: zip::read::ZipFile = archive.by_index(i)?; - let outpath: std::path::PathBuf = npcap_sdk_extract_dir.join(file.name()); - if (&*file.name()).ends_with('/') { - std::fs::create_dir_all(&outpath)?; - } else { - if let Some(p) = outpath.parent() { - if !p.exists() { - std::fs::create_dir_all(&p)?; - } - } - let mut outfile: File = std::fs::File::create(&outpath)?; - std::io::copy(&mut file, &mut outfile)?; - } - } - Ok(npcap_sdk_extract_dir) -} - -/// Add npcap SDK to LIB env var -pub fn add_npcap_sdk_to_lib(lib_dir_path: PathBuf) -> Result<(), Box> { - // Check lib dir exists - if !std::path::Path::new(&lib_dir_path).exists() { - return Err("Error: lib dir not found...".into()); - } - if !sys::check_env_lib_path(&lib_dir_path.to_str().unwrap()) { - match sys::add_env_lib_path(&lib_dir_path.to_str().unwrap()) { - Ok(_) => {} - Err(e) => Err(e)?, - } - } - Ok(()) -} diff --git a/deps/nex-npcap-helper/src/windows/sys.rs b/deps/nex-npcap-helper/src/windows/sys.rs deleted file mode 100644 index 7e179ba..0000000 --- a/deps/nex-npcap-helper/src/windows/sys.rs +++ /dev/null @@ -1,162 +0,0 @@ -use crate::app::AppInfo; -use std::collections::HashMap; -use winreg::enums::RegDisposition; -use winreg::enums::HKEY_LOCAL_MACHINE; -use winreg::RegKey; - -pub fn get_os_bit() -> String { - if cfg!(target_pointer_width = "32") { - return "32-bit".to_owned(); - } else if cfg!(target_pointer_width = "64") { - return "64-bit".to_owned(); - } else { - return "unknown".to_owned(); - } -} - -pub fn get_install_path(install_dir_name: &str) -> String { - match home::home_dir() { - Some(path) => { - let path: String = format!("{}\\{}", path.display(), install_dir_name); - path - } - None => String::new(), - } -} - -// Get software installation status -pub fn software_installed(software_name: String) -> bool { - let hklm: RegKey = RegKey::predef(HKEY_LOCAL_MACHINE); - let os_bit: String = get_os_bit(); - let npcap_key: RegKey = if os_bit == "32-bit" { - match hklm.open_subkey(format!("SOFTWARE\\{}", software_name)) { - Ok(key) => key, - Err(_) => return false, - } - } else { - match hklm.open_subkey(format!("SOFTWARE\\WOW6432Node\\{}", software_name)) { - Ok(key) => key, - Err(_) => return false, - } - }; - let _version: String = npcap_key.get_value("").unwrap_or(String::new()); - true -} - -#[allow(dead_code)] -pub fn get_installed_apps() -> HashMap { - let hklm: RegKey = winreg::RegKey::predef(HKEY_LOCAL_MACHINE); - let uninstall_key: RegKey = hklm - .open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") - .expect("key is missing"); - - let mut apps: HashMap = HashMap::new(); - for key in uninstall_key.enum_keys() { - let key = match key { - Ok(key) => key, - Err(_) => continue, - }; - //let key = key.unwrap(); - let subkey: RegKey = uninstall_key - .open_subkey(key.clone()) - .expect("key is missing"); - let app: AppInfo = AppInfo { - display_name: subkey.get_value("DisplayName").unwrap_or(String::new()), - display_version: subkey.get_value("DisplayVersion").unwrap_or(String::new()), - uninstall_string: subkey.get_value("UninstallString").unwrap_or(String::new()), - }; - apps.insert(key, app); - } - apps -} - -#[allow(dead_code)] -pub fn app_installed(app_name: String) -> bool { - let hklm: RegKey = winreg::RegKey::predef(HKEY_LOCAL_MACHINE); - let uninstall_key: RegKey = hklm - .open_subkey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall") - .expect("key is missing"); - - for key in uninstall_key.enum_keys() { - let key = match key { - Ok(key) => key, - Err(_) => continue, - }; - //let key = key.unwrap(); - let subkey: RegKey = uninstall_key - .open_subkey(key.clone()) - .expect("key is missing"); - let display_name: String = subkey.get_value("DisplayName").unwrap_or(String::new()); - if display_name == app_name { - return true; - } - } - false -} - -#[allow(dead_code)] -pub fn check_env_path(dir_path: &str) -> bool { - let reg_key: winreg::RegKey = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER) - .open_subkey_with_flags("Environment", winreg::enums::KEY_READ) - .unwrap(); - let reg_value: String = reg_key.get_value("Path").unwrap_or(String::new()); - reg_value.contains(dir_path) -} - -#[allow(dead_code)] -pub fn add_env_path(dir_path: &str) -> std::io::Result<()> { - let hkcu: winreg::RegKey = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER); - let (path, _): (winreg::RegKey, RegDisposition) = hkcu.create_subkey("Environment")?; - let mut path_value: String = path - .get_value::("Path") - .unwrap_or(String::new()); - if !path_value.is_empty() { - path_value.push(';'); - } - path_value.push_str(&std::path::Path::new(dir_path).to_str().unwrap()); - println!("{}", path_value); - path.set_value("Path", &path_value) -} - -pub fn check_env_lib_path(dir_path: &str) -> bool { - let reg_key: winreg::RegKey = match winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER) - .open_subkey_with_flags("Environment", winreg::enums::KEY_READ) - { - Ok(key) => key, - Err(_) => return false, - }; - let reg_value: String = reg_key.get_value("LIB").unwrap_or(String::new()); - reg_value.contains(dir_path) -} - -pub fn add_env_lib_path(dir_path: &str) -> std::io::Result<()> { - let hkcu: winreg::RegKey = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER); - let (path, _): (winreg::RegKey, RegDisposition) = hkcu.create_subkey("Environment")?; - let mut path_value: String = path - .get_value::("LIB") - .unwrap_or(String::new()); - if !path_value.is_empty() { - path_value.push(';'); - } - path_value.push_str(&std::path::Path::new(dir_path).to_str().unwrap()); - println!("{}", path_value); - path.set_value("LIB", &path_value) -} - -pub fn get_env_lib() -> String { - let reg_key: winreg::RegKey = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER) - .open_subkey_with_flags("Environment", winreg::enums::KEY_READ) - .unwrap(); - let reg_value: String = reg_key.get_value("LIB").unwrap_or(String::new()); - if !reg_value.is_empty() { - return reg_value; - } - let reg_key: winreg::RegKey = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE) - .open_subkey_with_flags( - "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", - winreg::enums::KEY_READ, - ) - .unwrap(); - let reg_value: String = reg_key.get_value("LIB").unwrap_or(String::new()); - reg_value -} diff --git a/examples/arp.rs b/examples/arp.rs index bd1fadf..4bbcdb7 100644 --- a/examples/arp.rs +++ b/examples/arp.rs @@ -67,7 +67,7 @@ fn main() { } }; - let src_ip: Ipv4Addr = interface.ipv4[0].addr.into(); + let src_ip: Ipv4Addr = interface.ipv4[0].addr(); // Create a channel to send/receive packet let (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) { diff --git a/examples/icmp_ping.rs b/examples/icmp_ping.rs index be5c455..65b7182 100644 --- a/examples/icmp_ping.rs +++ b/examples/icmp_ping.rs @@ -33,8 +33,8 @@ fn get_global_ipv6(interface: &Interface) -> Option { interface .ipv6 .iter() - .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr)) - .map(|ipv6| ipv6.addr) + .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr())) + .map(|ipv6| ipv6.addr()) } fn main() { @@ -76,7 +76,7 @@ fn main() { }; let use_tun: bool = interface.is_tun(); let src_ip: IpAddr = match dst_ip { - IpAddr::V4(_) => interface.ipv4[0].addr.into(), + IpAddr::V4(_) => interface.ipv4[0].addr().into(), IpAddr::V6(_) => { let ipv6 = get_global_ipv6(&interface).expect("Failed to get global IPv6 address"); ipv6.into() diff --git a/examples/list_interfaces.rs b/examples/list_interfaces.rs index f7f7d4a..c1b3b52 100644 --- a/examples/list_interfaces.rs +++ b/examples/list_interfaces.rs @@ -20,23 +20,28 @@ fn main() { println!("\t\tis BROADCAST {}", interface.is_broadcast()); println!("\t\tis POINT TO POINT {}", interface.is_point_to_point()); println!("\t\tis TUN {}", interface.is_tun()); + println!("\t\tis RUNNING {}", interface.is_running()); + println!("\t\tis PHYSICAL {}", interface.is_physical()); if let Some(mac_addr) = interface.mac_addr { println!("\tMAC Address: {}", mac_addr); } else { println!("\tMAC Address: (Failed to get mac address)"); } println!("\tIPv4: {:?}", interface.ipv4); - println!("\tIPv6: {:?}", interface.ipv6); + + // Print the IPv6 addresses with the scope ID after them as a suffix + let ipv6_strs: Vec = interface + .ipv6 + .iter() + .zip(interface.ipv6_scope_ids) + .map(|(ipv6, scope_id)| format!("{:?}%{}", ipv6, scope_id)) + .collect(); + println!("\tIPv6: [{}]", ipv6_strs.join(", ")); + println!("\tTransmit Speed: {:?}", interface.transmit_speed); println!("\tReceive Speed: {:?}", interface.receive_speed); - if let Some(gateway) = interface.gateway { - println!("Gateway"); - println!("\tMAC Address: {}", gateway.mac_addr); - println!("\tIPv4 Address: {:?}", gateway.ipv4); - println!("\tIPv6 Address: {:?}", gateway.ipv6); - } else { - println!("Gateway: (Not found)"); - } + println!("MTU: {:?}", interface.mtu); + println!("Default: {}", interface.default); println!(); } } diff --git a/examples/ndp.rs b/examples/ndp.rs index 4035671..7d47afe 100644 --- a/examples/ndp.rs +++ b/examples/ndp.rs @@ -71,7 +71,7 @@ fn main() { } }; - let src_ip: Ipv6Addr = interface.ipv6[0].addr.into(); + let src_ip: Ipv6Addr = interface.ipv6[0].addr(); // Create a channel to send/receive packet let (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) { diff --git a/examples/tcp_ping.rs b/examples/tcp_ping.rs index 5877ea3..5a65597 100644 --- a/examples/tcp_ping.rs +++ b/examples/tcp_ping.rs @@ -95,7 +95,7 @@ fn main() { IpAddr::V4(dst_ipv4) => match interface.ipv4.get(0) { Some(src_ipv4) => { let ipv4_packet_builder = - Ipv4PacketBuilder::new(src_ipv4.addr, dst_ipv4, IpNextLevelProtocol::Tcp); + Ipv4PacketBuilder::new(src_ipv4.addr(), dst_ipv4, IpNextLevelProtocol::Tcp); packet_builder.set_ipv4(ipv4_packet_builder); } None => { @@ -107,11 +107,11 @@ fn main() { match interface .ipv6 .iter() - .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr)) + .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr())) { Some(src_ipv6) => { let ipv6_packet_builder = - Ipv6PacketBuilder::new(src_ipv6.addr, dst_ipv6, IpNextLevelProtocol::Tcp); + Ipv6PacketBuilder::new(src_ipv6.addr(), dst_ipv6, IpNextLevelProtocol::Tcp); packet_builder.set_ipv6(ipv6_packet_builder); } None => { @@ -126,7 +126,7 @@ fn main() { IpAddr::V4(_dst_ipv4) => match interface.ipv4.get(0) { Some(src_ipv4) => { let mut tcp_packet_builder = TcpPacketBuilder::new( - SocketAddr::new(IpAddr::V4(src_ipv4.addr), 53443), + SocketAddr::new(IpAddr::V4(src_ipv4.addr()), 53443), target_socket, ); tcp_packet_builder.flags = TcpFlags::SYN; @@ -148,11 +148,11 @@ fn main() { match interface .ipv6 .iter() - .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr)) + .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr())) { Some(src_ipv6) => { let mut tcp_packet_builder = TcpPacketBuilder::new( - SocketAddr::new(IpAddr::V6(src_ipv6.addr), 53443), + SocketAddr::new(IpAddr::V6(src_ipv6.addr()), 53443), target_socket, ); tcp_packet_builder.flags = TcpFlags::SYN; diff --git a/examples/tls_stream.rs b/examples/tls_stream.rs deleted file mode 100644 index 049bda7..0000000 --- a/examples/tls_stream.rs +++ /dev/null @@ -1,62 +0,0 @@ -use nex_socket::tls::rustls::ClientConfig; -use nex_socket::tls::socket::TlsClient; - -use std::{ - io::{Read, Write}, - net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}, - time::Duration, -}; - -// connect to 1.1.1.1:443 using TLS and send a payload(HTTPS GET request) -fn main() { - let native_certs = nex_socket::tls::certs::get_native_certs().unwrap(); - let config = ClientConfig::builder() - .with_root_certificates(native_certs) - .with_no_client_auth(); - - // if you want to disable certificate verification - //nex_socket::tls::danger::disable_certificate_verification(&mut config, rustls::crypto::ring::default_provider()); - - // connect to one.one.one.one(1.1.1.1):443 and send a payload(HTTPS GET request) - let hostname = "one.one.one.one"; - let socket_addr: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), 443); - let stream: TcpStream = match TcpStream::connect(socket_addr) { - Ok(s) => s, - Err(e) => { - println!("connect error: {}", e); - return; - } - }; - match stream.set_read_timeout(Some(Duration::from_secs(1))) { - Ok(_) => {} - Err(e) => { - println!("set_read_timeout error: {}", e); - return; - } - } - let mut tls_client = TlsClient::new(hostname.to_string(), stream, config).unwrap(); - let req = format!( - "GET / HTTP/1.1\r\nHost: {}\r\nConnection: close\r\nAccept-Encoding: identity\r\n\r\n", - hostname - ); - - match tls_client.write_all(req.as_bytes()) { - Ok(_) => { - println!("payload sent. {} bytes", req.len()); - } - Err(e) => { - println!("write_all error: {}", e); - return; - } - } - - let mut res = Vec::new(); - match tls_client.read_to_end(&mut res) { - Ok(_) => {} - Err(e) => { - println!("read_to_end error: {}", e); - return; - } - } - println!("response: {}", String::from_utf8_lossy(&res)); -} diff --git a/examples/udp_ping.rs b/examples/udp_ping.rs index 2cc9a3c..2c52d50 100644 --- a/examples/udp_ping.rs +++ b/examples/udp_ping.rs @@ -100,7 +100,7 @@ fn main() { IpAddr::V4(dst_ipv4) => match interface.ipv4.get(0) { Some(src_ipv4) => { let ipv4_packet_builder = - Ipv4PacketBuilder::new(src_ipv4.addr, dst_ipv4, IpNextLevelProtocol::Udp); + Ipv4PacketBuilder::new(src_ipv4.addr(), dst_ipv4, IpNextLevelProtocol::Udp); packet_builder.set_ipv4(ipv4_packet_builder); } None => { @@ -112,11 +112,11 @@ fn main() { match interface .ipv6 .iter() - .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr)) + .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr())) { Some(src_ipv6) => { let ipv6_packet_builder = - Ipv6PacketBuilder::new(src_ipv6.addr, dst_ipv6, IpNextLevelProtocol::Udp); + Ipv6PacketBuilder::new(src_ipv6.addr(), dst_ipv6, IpNextLevelProtocol::Udp); packet_builder.set_ipv6(ipv6_packet_builder); } None => { @@ -131,7 +131,7 @@ fn main() { IpAddr::V4(_dst_ipv4) => match interface.ipv4.get(0) { Some(src_ipv4) => { let udp_packet_builder = UdpPacketBuilder::new( - SocketAddr::new(IpAddr::V4(src_ipv4.addr), SRC_PORT), + SocketAddr::new(IpAddr::V4(src_ipv4.addr()), SRC_PORT), SocketAddr::new(target_ip, DST_PORT), ); packet_builder.set_udp(udp_packet_builder); @@ -145,11 +145,11 @@ fn main() { match interface .ipv6 .iter() - .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr)) + .find(|ipv6| nex::net::ip::is_global_ipv6(&ipv6.addr())) { Some(src_ipv6) => { let udp_packet_builder = UdpPacketBuilder::new( - SocketAddr::new(IpAddr::V6(src_ipv6.addr), SRC_PORT), + SocketAddr::new(IpAddr::V6(src_ipv6.addr()), SRC_PORT), SocketAddr::new(target_ip, DST_PORT), ); packet_builder.set_udp(udp_packet_builder); diff --git a/nex-core/Cargo.toml b/nex-core/Cargo.toml index 0dbb2c9..49decfc 100644 --- a/nex-core/Cargo.toml +++ b/nex-core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-core" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "Core networking library for nex." repository = "https://github.com/shellrow/nex" @@ -11,8 +11,8 @@ categories = ["network-programming"] license = "MIT" [dependencies] -netdev = { version = "0.30" } -serde = { version = "1.0", features = ["derive"], optional = true } +netdev = { workspace = true } +serde = { workspace = true, features = ["derive"], optional = true } [features] serde = ["dep:serde", "netdev/serde"] diff --git a/nex-core/src/ip.rs b/nex-core/src/ip.rs index 35126bd..c6decdb 100644 --- a/nex-core/src/ip.rs +++ b/nex-core/src/ip.rs @@ -1,6 +1,6 @@ use std::net::{Ipv4Addr, Ipv6Addr}; -pub use netdev::ip::*; +pub use netdev::ipnet::*; pub fn is_global_ipv4(ipv4_addr: &Ipv4Addr) -> bool { !(ipv4_addr.octets()[0] == 0 // "This network" diff --git a/nex-datalink/Cargo.toml b/nex-datalink/Cargo.toml index bdbfca7..6beb9da 100644 --- a/nex-datalink/Cargo.toml +++ b/nex-datalink/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-datalink" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "Provides cross-platform datalink layer networking. Part of nex project." repository = "https://github.com/shellrow/nex" @@ -11,15 +11,15 @@ categories = ["network-programming"] license = "MIT" [dependencies] -libc = "0.2" -netdev = { version = "0.30" } -serde = { version = "1.0", features = ["derive"], optional = true } +libc = { workspace = true } +netdev = { workspace = true } +serde = { workspace = true, features = ["derive"], optional = true } pcap = { version = "2.0", optional = true } nex-core = { path = "../nex-core", version = "0.18.0" } nex-sys = { path = "../nex-sys", version = "0.18.0" } [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.52.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", diff --git a/nex-macro-helper/Cargo.toml b/nex-macro-helper/Cargo.toml index 3c0f090..42448da 100644 --- a/nex-macro-helper/Cargo.toml +++ b/nex-macro-helper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-macro-helper" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "A helper crate for nex-macro. Not intended for direct use." repository = "https://github.com/shellrow/nex" diff --git a/nex-macro/Cargo.toml b/nex-macro/Cargo.toml index 0cae345..db3b695 100644 --- a/nex-macro/Cargo.toml +++ b/nex-macro/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-macro" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "A macro for generating packet structures used by nex-packet. Not intended for direct use." repository = "https://github.com/shellrow/nex" @@ -17,7 +17,7 @@ proc-macro = true proc-macro2 = "1.0" quote = "1.0" syn = { version = "2.0", features = ["full"] } -regex = "1.10" +regex = "1.11" [dev-dependencies] nex-macro-helper = { path = "../nex-macro-helper", version = "0.18.0" } diff --git a/nex-packet-builder/Cargo.toml b/nex-packet-builder/Cargo.toml index a5d845e..3935221 100644 --- a/nex-packet-builder/Cargo.toml +++ b/nex-packet-builder/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-packet-builder" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "Provides high-level packet building on top of nex-packet. Part of nex project. " repository = "https://github.com/shellrow/nex" @@ -13,4 +13,4 @@ license = "MIT" [dependencies] nex-core = { path = "../nex-core", version = "0.18.0" } nex-packet = { path = "../nex-packet", version = "0.18.0" } -rand = "0.8" +rand = { workspace = true } diff --git a/nex-packet/Cargo.toml b/nex-packet/Cargo.toml index e08e592..391203f 100644 --- a/nex-packet/Cargo.toml +++ b/nex-packet/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-packet" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "Cross-platform packet parsing and building library. Provides low-level packet handling. Part of nex project." repository = "https://github.com/shellrow/nex" @@ -11,11 +11,12 @@ categories = ["network-programming"] license = "MIT" [dependencies] -rand = "0.8" -serde = { version = "1.0", features = ["derive"], optional = true } +rand = { workspace = true } +serde = { workspace = true, features = ["derive"], optional = true } nex-core = { path = "../nex-core", version = "0.18.0" } nex-macro = { path = "../nex-macro", version = "0.18.0" } nex-macro-helper = { path = "../nex-macro-helper", version = "0.18.0" } [features] +clippy = [] serde = ["dep:serde", "nex-core/serde"] diff --git a/nex-packet/src/util.rs b/nex-packet/src/util.rs index 7ba461b..d255ca9 100644 --- a/nex-packet/src/util.rs +++ b/nex-packet/src/util.rs @@ -224,21 +224,3 @@ mod tests { } } } - -#[cfg(all(test, feature = "benchmark"))] -mod checksum_benchmarks { - use super::checksum; - use test::{black_box, Bencher}; - - #[bench] - fn bench_checksum_small(b: &mut Bencher) { - let data = vec![99u8; 20]; - b.iter(|| checksum(black_box(&data), 5)); - } - - #[bench] - fn bench_checksum_large(b: &mut Bencher) { - let data = vec![123u8; 1024]; - b.iter(|| checksum(black_box(&data), 5)); - } -} diff --git a/nex-socket/Cargo.toml b/nex-socket/Cargo.toml index b523f56..82bb4a2 100644 --- a/nex-socket/Cargo.toml +++ b/nex-socket/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-socket" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "Cross-platform socket library. Part of nex project. Offers socket-related functionality." repository = "https://github.com/shellrow/nex" @@ -11,17 +11,14 @@ categories = ["network-programming"] license = "MIT" [dependencies] -async-io = "2.3" -futures-lite = "2.3" +async-io = { workspace = true } +futures-lite = "2.6" futures-io = "0.3" socket2 = { version = "0.5", features = ["all"] } nex-packet = { path = "../nex-packet", version = "0.18.0" } -rustls = { version = "0.23", default-features = false, features = ["logging", "std", "tls12"], optional = true } -rustls-native-certs = { version = "0.7", optional = true } -rustls-pki-types = { version = "1.7", optional = true } [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.52.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", @@ -29,7 +26,3 @@ features = [ "Win32_System_Threading", "Win32_System_WindowsProgramming", ] - -[features] -tls = ["rustls/ring", "dep:rustls-native-certs", "dep:rustls-pki-types"] -tls-aws-lc = ["rustls/aws_lc_rs", "dep:rustls-native-certs", "dep:rustls-pki-types"] diff --git a/nex-socket/src/lib.rs b/nex-socket/src/lib.rs index 8f4ed77..a6f18c5 100644 --- a/nex-socket/src/lib.rs +++ b/nex-socket/src/lib.rs @@ -1,9 +1,6 @@ mod socket; mod sys; -#[cfg(any(feature = "tls", feature = "tls-ring"))] -pub mod tls; - pub use socket::AsyncSocket; pub use socket::AsyncTcpStream; pub use socket::IpVersion; diff --git a/nex-socket/src/tls/certs.rs b/nex-socket/src/tls/certs.rs deleted file mode 100644 index 8342f0f..0000000 --- a/nex-socket/src/tls/certs.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::io; - -/// Get the native certificates from the system. return rustls::RootCertStore -pub fn get_native_certs() -> io::Result { - let mut root_store = rustls::RootCertStore::empty(); - match rustls_native_certs::load_native_certs() { - Ok(certs) => { - for cert in certs { - match root_store.add(cert) { - Ok(_) => {} - Err(_) => {} - } - } - Ok(root_store) - } - Err(e) => return Err(e), - } -} diff --git a/nex-socket/src/tls/client.rs b/nex-socket/src/tls/client.rs deleted file mode 100644 index 6a52f5d..0000000 --- a/nex-socket/src/tls/client.rs +++ /dev/null @@ -1,240 +0,0 @@ -use super::session::IoSession; -use super::state::TlsState; -use super::stream::Stream; -use futures_io::{AsyncRead, AsyncWrite}; -use rustls::ClientConnection; -#[cfg(unix)] -use std::os::unix::io::{AsRawFd, RawFd}; -#[cfg(windows)] -use std::os::windows::io::{AsRawSocket, RawSocket}; -use std::{ - io, - pin::Pin, - task::{Context, Poll}, -}; - -/// A wrapper around an underlying raw stream which implements the TLS or SSL -#[derive(Debug)] -pub struct TlsStream { - pub(crate) io: IO, - pub(crate) session: ClientConnection, - pub(crate) state: TlsState, - #[cfg(feature = "early-data")] - pub(crate) early_waker: Option, -} - -impl TlsStream { - #[inline] - pub fn get_ref(&self) -> (&IO, &ClientConnection) { - (&self.io, &self.session) - } - - #[inline] - pub fn get_mut(&mut self) -> (&mut IO, &mut ClientConnection) { - (&mut self.io, &mut self.session) - } - - #[inline] - pub fn into_inner(self) -> (IO, ClientConnection) { - (self.io, self.session) - } -} - -#[cfg(unix)] -impl AsRawFd for TlsStream -where - S: AsRawFd, -{ - fn as_raw_fd(&self) -> RawFd { - self.get_ref().0.as_raw_fd() - } -} - -#[cfg(windows)] -impl AsRawSocket for TlsStream -where - S: AsRawSocket, -{ - fn as_raw_socket(&self) -> RawSocket { - self.get_ref().0.as_raw_socket() - } -} - -impl IoSession for TlsStream { - type Io = IO; - type Session = ClientConnection; - - #[inline] - fn skip_handshake(&self) -> bool { - self.state.is_early_data() - } - - #[inline] - fn get_mut(&mut self) -> (&mut TlsState, &mut Self::Io, &mut Self::Session) { - (&mut self.state, &mut self.io, &mut self.session) - } - - #[inline] - fn into_io(self) -> Self::Io { - self.io - } -} - -impl AsyncRead for TlsStream -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - match self.state { - #[cfg(feature = "early-data")] - TlsState::EarlyData(..) => { - let this = self.get_mut(); - if this - .early_waker - .as_ref() - .filter(|waker| cx.waker().will_wake(waker)) - .is_none() - { - this.early_waker = Some(cx.waker().clone()); - } - - Poll::Pending - } - TlsState::Stream | TlsState::WriteShutdown => { - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - - match stream.as_mut_pin().poll_read(cx, buf) { - Poll::Ready(Ok(n)) => { - if n == 0 || stream.eof { - this.state.shutdown_read(); - } - - Poll::Ready(Ok(n)) - } - Poll::Ready(Err(err)) if err.kind() == io::ErrorKind::ConnectionAborted => { - this.state.shutdown_read(); - Poll::Ready(Err(err)) - } - output => output, - } - } - TlsState::ReadShutdown | TlsState::FullyShutdown => Poll::Ready(Ok(0)), - } - } -} - -impl AsyncWrite for TlsStream -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - - #[allow(clippy::match_single_binding)] - match this.state { - #[cfg(feature = "early-data")] - TlsState::EarlyData(ref mut pos, ref mut data) => { - use std::io::Write; - - // Write early data - if let Some(mut early_data) = stream.session.early_data() { - let len = match early_data.write(buf) { - Ok(n) => n, - Err(err) => return Poll::Ready(Err(err)), - }; - if len != 0 { - data.extend_from_slice(&buf[..len]); - return Poll::Ready(Ok(len)); - } - } - - // Complete handshake - while stream.session.is_handshaking() { - ready!(stream.handshake(cx))?; - } - - // Write early data - if !stream.session.is_early_data_accepted() { - while *pos < data.len() { - let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; - *pos += len; - } - } - - // Update state - this.state = TlsState::Stream; - - if let Some(waker) = this.early_waker.take() { - waker.wake(); - } - - stream.as_mut_pin().poll_write(cx, buf) - } - _ => stream.as_mut_pin().poll_write(cx, buf), - } - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - - #[cfg(feature = "early-data")] - { - if let TlsState::EarlyData(ref mut pos, ref mut data) = this.state { - // Complete handshake - while stream.session.is_handshaking() { - ready!(stream.handshake(cx))?; - } - - // Write early data - if !stream.session.is_early_data_accepted() { - while *pos < data.len() { - let len = ready!(stream.as_mut_pin().poll_write(cx, &data[*pos..]))?; - *pos += len; - } - } - - this.state = TlsState::Stream; - - if let Some(waker) = this.early_waker.take() { - waker.wake(); - } - } - } - - stream.as_mut_pin().poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - #[cfg(feature = "early-data")] - { - // Complete handshake - if matches!(self.state, TlsState::EarlyData(..)) { - ready!(self.as_mut().poll_flush(cx))?; - } - } - - if self.state.writeable() { - self.session.send_close_notify(); - self.state.shutdown_write(); - } - - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - stream.as_mut_pin().poll_close(cx) - } -} diff --git a/nex-socket/src/tls/danger.rs b/nex-socket/src/tls/danger.rs deleted file mode 100644 index 81f9103..0000000 --- a/nex-socket/src/tls/danger.rs +++ /dev/null @@ -1,83 +0,0 @@ -use rustls::client::danger::{ - DangerousClientConfig, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, -}; -use rustls::crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider}; -use rustls::ClientConfig; -use rustls::DigitallySignedStruct; -use rustls_pki_types::{CertificateDer, ServerName, UnixTime}; -use std::sync::Arc; - -/// A certificate verifier that does not perform any verification. -#[derive(Debug, Clone)] -pub struct NoCertificateVerification(CryptoProvider); - -impl NoCertificateVerification { - pub fn new(provider: CryptoProvider) -> Self { - Self(provider) - } -} - -impl ServerCertVerifier for NoCertificateVerification { - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp: &[u8], - _now: UnixTime, - ) -> Result { - Ok(ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls12_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls13_signature( - message, - cert, - dss, - &self.0.signature_verification_algorithms, - ) - } - - fn supported_verify_schemes(&self) -> Vec { - self.0.signature_verification_algorithms.supported_schemes() - } -} - -/// Get the dangerous client config. Return rustls::ClientConfig -pub fn get_dangerous_client_config( - root_store: rustls::RootCertStore, - provider: CryptoProvider, -) -> ClientConfig { - let mut config = rustls::ClientConfig::builder() - .with_root_certificates(root_store) - .with_no_client_auth(); - let mut dangerous_config: DangerousClientConfig = rustls::ClientConfig::dangerous(&mut config); - // Disable certificate verification - dangerous_config.set_certificate_verifier(Arc::new(NoCertificateVerification::new(provider))); - config -} - -/// Disable certificate verification -pub fn disable_certificate_verification(config: &mut ClientConfig, provider: CryptoProvider) { - let mut dangerous_config: DangerousClientConfig = rustls::ClientConfig::dangerous(config); - dangerous_config.set_certificate_verifier(Arc::new(NoCertificateVerification::new(provider))); -} diff --git a/nex-socket/src/tls/mod.rs b/nex-socket/src/tls/mod.rs deleted file mode 100644 index 7f4cac9..0000000 --- a/nex-socket/src/tls/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod certs; -pub(crate) mod client; -pub mod danger; -pub(crate) mod server; -pub(crate) mod session; -pub mod socket; -pub(crate) mod state; -pub(crate) mod stream; - -pub use rustls; -pub use rustls_pki_types as pki_types; - -pub use socket::TlsClient; -pub use socket::TlsServer; diff --git a/nex-socket/src/tls/server.rs b/nex-socket/src/tls/server.rs deleted file mode 100644 index 69f5588..0000000 --- a/nex-socket/src/tls/server.rs +++ /dev/null @@ -1,150 +0,0 @@ -use futures_io::{AsyncRead, AsyncWrite}; -use rustls::ServerConnection; -use std::io; -#[cfg(unix)] -use std::os::unix::io::{AsRawFd, RawFd}; -#[cfg(windows)] -use std::os::windows::io::{AsRawSocket, RawSocket}; -use std::pin::Pin; -use std::task::{Context, Poll}; - -use super::session::IoSession; -use super::state::TlsState; -use super::stream::Stream; - -/// A wrapper around an underlying raw stream which implements the TLS or SSL -#[derive(Debug)] -pub struct TlsStream { - pub(crate) io: IO, - pub(crate) session: ServerConnection, - pub(crate) state: TlsState, -} - -impl TlsStream { - #[inline] - pub fn get_ref(&self) -> (&IO, &ServerConnection) { - (&self.io, &self.session) - } - - #[inline] - pub fn get_mut(&mut self) -> (&mut IO, &mut ServerConnection) { - (&mut self.io, &mut self.session) - } - - #[inline] - pub fn into_inner(self) -> (IO, ServerConnection) { - (self.io, self.session) - } -} - -impl IoSession for TlsStream { - type Io = IO; - type Session = ServerConnection; - - #[inline] - fn skip_handshake(&self) -> bool { - false - } - - #[inline] - fn get_mut(&mut self) -> (&mut TlsState, &mut Self::Io, &mut Self::Session) { - (&mut self.state, &mut self.io, &mut self.session) - } - - #[inline] - fn into_io(self) -> Self::Io { - self.io - } -} - -impl AsyncRead for TlsStream -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - - match &this.state { - TlsState::Stream | TlsState::WriteShutdown => { - match stream.as_mut_pin().poll_read(cx, buf) { - Poll::Ready(Ok(n)) => { - if n == 0 || stream.eof { - this.state.shutdown_read(); - } - - Poll::Ready(Ok(n)) - } - Poll::Ready(Err(err)) if err.kind() == io::ErrorKind::UnexpectedEof => { - this.state.shutdown_read(); - Poll::Ready(Err(err)) - } - output => output, - } - } - TlsState::ReadShutdown | TlsState::FullyShutdown => Poll::Ready(Ok(0)), - #[cfg(feature = "early-data")] - s => unreachable!("server TLS can not hit this state: {:?}", s), - } - } -} - -impl AsyncWrite for TlsStream -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - stream.as_mut_pin().poll_write(cx, buf) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - stream.as_mut_pin().poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - if self.state.writeable() { - self.session.send_close_notify(); - self.state.shutdown_write(); - } - - let this = self.get_mut(); - let mut stream = - Stream::new(&mut this.io, &mut this.session).set_eof(!this.state.readable()); - stream.as_mut_pin().poll_close(cx) - } -} - -#[cfg(unix)] -impl AsRawFd for TlsStream -where - IO: AsRawFd, -{ - fn as_raw_fd(&self) -> RawFd { - self.get_ref().0.as_raw_fd() - } -} - -#[cfg(windows)] -impl AsRawSocket for TlsStream -where - IO: AsRawSocket, -{ - fn as_raw_socket(&self) -> RawSocket { - self.get_ref().0.as_raw_socket() - } -} diff --git a/nex-socket/src/tls/session.rs b/nex-socket/src/tls/session.rs deleted file mode 100644 index 7f76347..0000000 --- a/nex-socket/src/tls/session.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::state::TlsState; -use super::stream::{Stream, SyncWriteAdapter}; -use futures_io::{AsyncRead, AsyncWrite}; -use rustls::server::AcceptedAlert; -use rustls::{ConnectionCommon, SideData}; -use std::future::Future; -use std::ops::{Deref, DerefMut}; -use std::pin::Pin; -use std::task::{Context, Poll}; -use std::{io, mem}; - -pub(crate) trait IoSession { - type Io; - type Session; - - fn skip_handshake(&self) -> bool; - fn get_mut(&mut self) -> (&mut TlsState, &mut Self::Io, &mut Self::Session); - fn into_io(self) -> Self::Io; -} - -pub(crate) enum MidHandshake { - Handshaking(IS), - End, - SendAlert { - io: IS::Io, - alert: AcceptedAlert, - error: io::Error, - }, - Error { - io: IS::Io, - error: io::Error, - }, -} - -impl Future for MidHandshake -where - IS: IoSession + Unpin, - IS::Io: AsyncRead + AsyncWrite + Unpin, - IS::Session: DerefMut + Deref> + Unpin, - SD: SideData, -{ - type Output = Result; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.get_mut(); - - let mut stream = match mem::replace(this, MidHandshake::End) { - MidHandshake::Handshaking(stream) => stream, - MidHandshake::SendAlert { - mut io, - mut alert, - error, - } => loop { - match alert.write(&mut SyncWriteAdapter { io: &mut io, cx }) { - Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - *this = MidHandshake::SendAlert { io, error, alert }; - return Poll::Pending; - } - Err(_) | Ok(0) => return Poll::Ready(Err((error, io))), - Ok(_) => {} - }; - }, - // Starting the handshake returned an error; fail the future immediately. - MidHandshake::Error { io, error } => return Poll::Ready(Err((error, io))), - _ => panic!("unexpected polling after handshake"), - }; - - if !stream.skip_handshake() { - let (state, io, session) = stream.get_mut(); - let mut tls_stream = Stream::new(io, session).set_eof(!state.readable()); - - macro_rules! try_poll { - ( $e:expr ) => { - match $e { - Poll::Ready(Ok(_)) => (), - Poll::Ready(Err(err)) => return Poll::Ready(Err((err, stream.into_io()))), - Poll::Pending => { - *this = MidHandshake::Handshaking(stream); - return Poll::Pending; - } - } - }; - } - - while tls_stream.session.is_handshaking() { - try_poll!(tls_stream.handshake(cx)); - } - - try_poll!(Pin::new(&mut tls_stream).poll_flush(cx)); - } - - Poll::Ready(Ok(stream)) - } -} diff --git a/nex-socket/src/tls/socket.rs b/nex-socket/src/tls/socket.rs deleted file mode 100644 index a6339ff..0000000 --- a/nex-socket/src/tls/socket.rs +++ /dev/null @@ -1,595 +0,0 @@ -use super::client; -use super::server; -use super::session::MidHandshake; -use super::state; -use super::stream::{SyncReadAdapter, SyncWriteAdapter}; - -use futures_io::{AsyncRead, AsyncWrite}; -use rustls::server::AcceptedAlert; -use rustls::ConnectionCommon; -use rustls::{ClientConfig, ClientConnection, CommonState, ServerConfig, ServerConnection}; -use state::TlsState; -use std::future::Future; -use std::io; -use std::net::TcpStream; -use std::ops::Deref; -use std::ops::DerefMut; -#[cfg(unix)] -use std::os::unix::io::{AsRawFd, RawFd}; -#[cfg(windows)] -use std::os::windows::io::{AsRawSocket, RawSocket}; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll}; - -use super::pki_types; - -/// Get TLS Client. Return rustls::StreamOwned -fn get_tls_client( - hostname: String, - socket: TcpStream, - config: ClientConfig, -) -> io::Result> { - let server_name = match pki_types::ServerName::try_from(hostname) { - Ok(s) => s, - Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), - }; - let tls_connection: rustls::ClientConnection = - rustls::ClientConnection::new(Arc::new(config), server_name) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - let stream = rustls::StreamOwned::new(tls_connection, socket); - Ok(stream) -} - -/// Get TLS Server. Return rustls::StreamOwned -fn get_tls_server( - socket: TcpStream, - config: ServerConfig, -) -> io::Result> { - let tls_connection: rustls::ServerConnection = rustls::ServerConnection::new(Arc::new(config)) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - let stream = rustls::StreamOwned::new(tls_connection, socket); - Ok(stream) -} - -pub struct TlsStream -where - C: DerefMut + Deref>, - T: io::Read + io::Write, -{ - pub(crate) stream: rustls::StreamOwned, -} - -impl io::Read for TlsStream -where - C: DerefMut + Deref>, - T: io::Read + io::Write, -{ - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.stream.sock.read(buf) - } -} - -impl io::Write for TlsStream -where - C: DerefMut + Deref>, - T: io::Read + io::Write, -{ - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.stream.sock.write(buf) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - self.stream.sock.flush() - } -} - -impl TlsStream -where - C: DerefMut + Deref>, - T: io::Read + io::Write, -{ - pub fn new(stream: rustls::StreamOwned) -> TlsStream { - TlsStream { stream } - } -} - -/// Wrapper around a `rustls::StreamOwned` -pub struct TlsClient { - pub(crate) stream: rustls::StreamOwned, -} - -impl io::Read for TlsClient { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.stream.read(buf) - } -} - -impl io::Write for TlsClient { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.stream.write(buf) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - self.stream.flush() - } -} - -impl TlsClient { - pub fn new(hostname: String, socket: TcpStream, config: ClientConfig) -> io::Result { - match get_tls_client(hostname, socket, config) { - Ok(stream) => Ok(TlsClient { stream }), - Err(e) => Err(e), - } - } -} - -/// Wrapper around a `rustls::StreamOwned` -pub struct TlsServer { - pub(crate) stream: rustls::StreamOwned, -} - -impl io::Read for TlsServer { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.stream.read(buf) - } -} - -impl io::Write for TlsServer { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.stream.write(buf) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - self.stream.flush() - } -} - -impl TlsServer { - pub fn new(socket: TcpStream, config: ServerConfig) -> io::Result { - match get_tls_server(socket, config) { - Ok(stream) => Ok(TlsServer { stream }), - Err(e) => Err(e), - } - } -} - -/// Async TLS connector. -/// A wrapper around a `rustls::ClientConfig` -#[derive(Clone)] -pub struct AsyncTlsConnector { - inner: Arc, - #[cfg(feature = "early-data")] - early_data: bool, -} -/// Async TLS acceptor. -/// A wrapper around a `rustls::ServerConfig` -#[derive(Clone)] -pub struct AsyncTlsAcceptor { - inner: Arc, -} - -impl From> for AsyncTlsConnector { - fn from(inner: Arc) -> AsyncTlsConnector { - AsyncTlsConnector { - inner, - #[cfg(feature = "early-data")] - early_data: false, - } - } -} - -impl From> for AsyncTlsAcceptor { - fn from(inner: Arc) -> AsyncTlsAcceptor { - AsyncTlsAcceptor { inner } - } -} - -impl AsyncTlsConnector { - #[cfg(feature = "early-data")] - pub fn early_data(mut self, flag: bool) -> TlsConnector { - self.early_data = flag; - self - } - - #[inline] - pub fn connect( - &self, - server_name: pki_types::ServerName<'static>, - stream: IO, - ) -> Connect - where - IO: AsyncRead + AsyncWrite + Unpin, - { - self.connect_with(server_name, stream, |_| ()) - } - - pub fn connect_with( - &self, - server_name: pki_types::ServerName<'static>, - stream: IO, - f: F, - ) -> Connect - where - IO: AsyncRead + AsyncWrite + Unpin, - F: FnOnce(&mut ClientConnection), - { - let mut session = match ClientConnection::new(self.inner.clone(), server_name) { - Ok(session) => session, - Err(error) => { - return Connect(MidHandshake::Error { - io: stream, - error: io::Error::new(io::ErrorKind::Other, error), - }); - } - }; - f(&mut session); - - Connect(MidHandshake::Handshaking(client::TlsStream { - io: stream, - - #[cfg(not(feature = "early-data"))] - state: TlsState::Stream, - - #[cfg(feature = "early-data")] - state: if self.early_data && session.early_data().is_some() { - TlsState::EarlyData(0, Vec::new()) - } else { - TlsState::Stream - }, - - #[cfg(feature = "early-data")] - early_waker: None, - - session, - })) - } -} - -impl AsyncTlsAcceptor { - #[inline] - pub fn accept(&self, stream: IO) -> Accept - where - IO: AsyncRead + AsyncWrite + Unpin, - { - self.accept_with(stream, |_| ()) - } - - pub fn accept_with(&self, stream: IO, f: F) -> Accept - where - IO: AsyncRead + AsyncWrite + Unpin, - F: FnOnce(&mut ServerConnection), - { - let mut session = match ServerConnection::new(self.inner.clone()) { - Ok(session) => session, - Err(error) => { - return Accept(MidHandshake::Error { - io: stream, - error: io::Error::new(io::ErrorKind::Other, error), - }); - } - }; - f(&mut session); - - Accept(MidHandshake::Handshaking(server::TlsStream { - session, - io: stream, - state: TlsState::Stream, - })) - } -} - -pub struct LazyConfigAcceptor { - acceptor: rustls::server::Acceptor, - io: Option, - alert: Option<(rustls::Error, AcceptedAlert)>, -} - -impl LazyConfigAcceptor -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - #[inline] - pub fn new(acceptor: rustls::server::Acceptor, io: IO) -> Self { - Self { - acceptor, - io: Some(io), - alert: None, - } - } -} - -impl Future for LazyConfigAcceptor -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - type Output = Result, io::Error>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let this = self.get_mut(); - loop { - let io = match this.io.as_mut() { - Some(io) => io, - None => { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::Other, - "acceptor cannot be polled after acceptance", - ))) - } - }; - - if let Some((err, mut alert)) = this.alert.take() { - match alert.write(&mut SyncWriteAdapter { io, cx }) { - Err(e) if e.kind() == io::ErrorKind::WouldBlock => { - this.alert = Some((err, alert)); - return Poll::Pending; - } - Ok(0) | Err(_) => { - return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidData, err))) - } - Ok(_) => { - this.alert = Some((err, alert)); - continue; - } - }; - } - - let mut reader = SyncReadAdapter { io, cx }; - match this.acceptor.read_tls(&mut reader) { - Ok(0) => return Err(io::ErrorKind::UnexpectedEof.into()).into(), - Ok(_) => {} - Err(e) if e.kind() == io::ErrorKind::WouldBlock => return Poll::Pending, - Err(e) => return Err(e).into(), - } - - match this.acceptor.accept() { - Ok(Some(accepted)) => { - let io = this.io.take().unwrap(); - return Poll::Ready(Ok(StartHandshake { accepted, io })); - } - Ok(None) => {} - Err((err, alert)) => { - this.alert = Some((err, alert)); - } - } - } - } -} - -pub struct StartHandshake { - accepted: rustls::server::Accepted, - io: IO, -} - -impl StartHandshake -where - IO: AsyncRead + AsyncWrite + Unpin, -{ - pub fn client_hello(&self) -> rustls::server::ClientHello<'_> { - self.accepted.client_hello() - } - - pub fn into_stream(self, config: Arc) -> Accept { - self.into_stream_with(config, |_| ()) - } - - pub fn into_stream_with(self, config: Arc, f: F) -> Accept - where - F: FnOnce(&mut ServerConnection), - { - let mut conn = match self.accepted.into_connection(config) { - Ok(conn) => conn, - Err((error, alert)) => { - return Accept(MidHandshake::SendAlert { - io: self.io, - error: io::Error::new(io::ErrorKind::Other, error), - alert, - }); - } - }; - f(&mut conn); - - Accept(MidHandshake::Handshaking(server::TlsStream { - session: conn, - io: self.io, - state: TlsState::Stream, - })) - } -} - -/// Future returned from `TlsConnector::connect` which will resolve -/// once the connection handshake has finished. -pub struct Connect(MidHandshake>); - -/// Future returned from `TlsAcceptor::accept` which will resolve -/// once the accept handshake has finished. -pub struct Accept(MidHandshake>); - -/// Connect future that resolves to a `TlsStream` on success. -/// If the handshake fails, the IO is returned. -pub struct FallibleConnect(MidHandshake>); - -/// Accept future that resolves to a `TlsStream` on success. -/// If the handshake fails, the IO is returned. -pub struct FallibleAccept(MidHandshake>); - -impl Connect { - #[inline] - pub fn into_fallible(self) -> FallibleConnect { - FallibleConnect(self.0) - } -} - -impl Accept { - #[inline] - pub fn into_fallible(self) -> FallibleAccept { - FallibleAccept(self.0) - } -} - -impl Future for Connect { - type Output = io::Result>; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx).map_err(|(err, _)| err) - } -} - -impl Future for Accept { - type Output = io::Result>; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx).map_err(|(err, _)| err) - } -} - -impl Future for FallibleConnect { - type Output = Result, (io::Error, IO)>; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx) - } -} - -impl Future for FallibleAccept { - type Output = Result, (io::Error, IO)>; - - #[inline] - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - Pin::new(&mut self.0).poll(cx) - } -} - -/// Abstructed TLS stream. -/// -/// Abstruction over the different types of TLS streams that can be created by -/// the `TlsConnector` and `TlsAcceptor`. -#[derive(Debug)] -pub enum AsyncTlsStream { - Client(client::TlsStream), - Server(server::TlsStream), -} - -impl AsyncTlsStream { - pub fn get_ref(&self) -> (&T, &CommonState) { - use AsyncTlsStream::*; - match self { - Client(io) => { - let (io, session) = io.get_ref(); - (io, &*session) - } - Server(io) => { - let (io, session) = io.get_ref(); - (io, &*session) - } - } - } - - pub fn get_mut(&mut self) -> (&mut T, &mut CommonState) { - use AsyncTlsStream::*; - match self { - Client(io) => { - let (io, session) = io.get_mut(); - (io, &mut *session) - } - Server(io) => { - let (io, session) = io.get_mut(); - (io, &mut *session) - } - } - } -} - -impl From> for AsyncTlsStream { - fn from(s: client::TlsStream) -> Self { - Self::Client(s) - } -} - -impl From> for AsyncTlsStream { - fn from(s: server::TlsStream) -> Self { - Self::Server(s) - } -} - -#[cfg(unix)] -impl AsRawFd for AsyncTlsStream -where - S: AsRawFd, -{ - fn as_raw_fd(&self) -> RawFd { - self.get_ref().0.as_raw_fd() - } -} - -#[cfg(windows)] -impl AsRawSocket for AsyncTlsStream -where - S: AsRawSocket, -{ - fn as_raw_socket(&self) -> RawSocket { - self.get_ref().0.as_raw_socket() - } -} - -impl AsyncRead for AsyncTlsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - #[inline] - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - match self.get_mut() { - AsyncTlsStream::Client(x) => Pin::new(x).poll_read(cx, buf), - AsyncTlsStream::Server(x) => Pin::new(x).poll_read(cx, buf), - } - } -} - -impl AsyncWrite for AsyncTlsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - #[inline] - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - match self.get_mut() { - AsyncTlsStream::Client(x) => Pin::new(x).poll_write(cx, buf), - AsyncTlsStream::Server(x) => Pin::new(x).poll_write(cx, buf), - } - } - - #[inline] - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.get_mut() { - AsyncTlsStream::Client(x) => Pin::new(x).poll_flush(cx), - AsyncTlsStream::Server(x) => Pin::new(x).poll_flush(cx), - } - } - - #[inline] - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.get_mut() { - AsyncTlsStream::Client(x) => Pin::new(x).poll_close(cx), - AsyncTlsStream::Server(x) => Pin::new(x).poll_close(cx), - } - } -} diff --git a/nex-socket/src/tls/state.rs b/nex-socket/src/tls/state.rs deleted file mode 100644 index 8112398..0000000 --- a/nex-socket/src/tls/state.rs +++ /dev/null @@ -1,49 +0,0 @@ -#[derive(Debug)] -pub enum TlsState { - #[cfg(feature = "early-data")] - EarlyData(usize, Vec), - Stream, - ReadShutdown, - WriteShutdown, - FullyShutdown, -} - -impl TlsState { - #[inline] - pub fn shutdown_read(&mut self) { - match *self { - TlsState::WriteShutdown | TlsState::FullyShutdown => *self = TlsState::FullyShutdown, - _ => *self = TlsState::ReadShutdown, - } - } - - #[inline] - pub fn shutdown_write(&mut self) { - match *self { - TlsState::ReadShutdown | TlsState::FullyShutdown => *self = TlsState::FullyShutdown, - _ => *self = TlsState::WriteShutdown, - } - } - - #[inline] - pub fn writeable(&self) -> bool { - !matches!(*self, TlsState::WriteShutdown | TlsState::FullyShutdown) - } - - #[inline] - pub fn readable(&self) -> bool { - !matches!(*self, TlsState::ReadShutdown | TlsState::FullyShutdown) - } - - #[inline] - #[cfg(feature = "early-data")] - pub fn is_early_data(&self) -> bool { - matches!(self, TlsState::EarlyData(..)) - } - - #[inline] - #[cfg(not(feature = "early-data"))] - pub const fn is_early_data(&self) -> bool { - false - } -} diff --git a/nex-socket/src/tls/stream.rs b/nex-socket/src/tls/stream.rs deleted file mode 100644 index 2f9456c..0000000 --- a/nex-socket/src/tls/stream.rs +++ /dev/null @@ -1,343 +0,0 @@ -use futures_io::{AsyncRead, AsyncWrite}; -use rustls::{ConnectionCommon, SideData}; -use std::io::{self, IoSlice, Read, Write}; -use std::ops::{Deref, DerefMut}; -use std::pin::Pin; -use std::task::{Context, Poll}; - -macro_rules! ready { - ( $e:expr ) => { - match $e { - std::task::Poll::Ready(t) => t, - std::task::Poll::Pending => return std::task::Poll::Pending, - } - }; -} - -pub struct Stream<'a, IO, C> { - pub io: &'a mut IO, - pub session: &'a mut C, - pub eof: bool, -} - -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, C, SD> Stream<'a, IO, C> -where - C: DerefMut + Deref>, - SD: SideData, -{ - pub fn new(io: &'a mut IO, session: &'a mut C) -> Self { - Stream { - io, - session, - eof: false, - } - } - - pub fn set_eof(mut self, eof: bool) -> Self { - self.eof = eof; - self - } - - pub fn as_mut_pin(&mut self) -> Pin<&mut Self> { - Pin::new(self) - } - - pub fn read_io(&mut self, cx: &mut Context) -> Poll> { - struct Reader<'a, 'b, T> { - io: &'a mut T, - cx: &'a mut Context<'b>, - } - - impl<'a, 'b, T: AsyncRead + Unpin> Read for Reader<'a, 'b, T> { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match Pin::new(&mut self.io).poll_read(self.cx, buf) { - Poll::Ready(Ok(n)) => Ok(n), - Poll::Ready(Err(err)) => Err(err), - Poll::Pending => Err(io::ErrorKind::WouldBlock.into()), - } - } - } - - let mut reader = Reader { io: self.io, cx }; - - let n = match self.session.read_tls(&mut reader) { - Ok(n) => n, - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return Poll::Pending, - Err(err) => return Poll::Ready(Err(err)), - }; - - let stats = self.session.process_new_packets().map_err(|err| { - let _ = self.write_io(cx); - - io::Error::new(io::ErrorKind::InvalidData, err) - })?; - - if stats.peer_has_closed() && self.session.is_handshaking() { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "tls handshake alert", - ))); - } - - Poll::Ready(Ok(n)) - } - - pub fn write_io(&mut self, cx: &mut Context) -> Poll> { - struct Writer<'a, 'b, T> { - io: &'a mut T, - cx: &'a mut Context<'b>, - } - - impl<'a, 'b, T: Unpin> Writer<'a, 'b, T> { - #[inline] - fn poll_with( - &mut self, - f: impl FnOnce(Pin<&mut T>, &mut Context<'_>) -> Poll>, - ) -> io::Result { - match f(Pin::new(&mut self.io), self.cx) { - Poll::Ready(result) => result, - Poll::Pending => Err(io::ErrorKind::WouldBlock.into()), - } - } - } - - impl<'a, 'b, T: AsyncWrite + Unpin> Write for Writer<'a, 'b, T> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.poll_with(|io, cx| io.poll_write(cx, buf)) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.poll_with(|io, cx| io.poll_write_vectored(cx, bufs)) - } - - fn flush(&mut self) -> io::Result<()> { - self.poll_with(|io, cx| io.poll_flush(cx)) - } - } - - let mut writer = Writer { io: self.io, cx }; - - match self.session.write_tls(&mut writer) { - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending, - result => Poll::Ready(result), - } - } - - pub fn handshake(&mut self, cx: &mut Context) -> Poll> { - let mut wrlen = 0; - let mut rdlen = 0; - - loop { - let mut write_would_block = false; - let mut read_would_block = false; - let mut need_flush = false; - - while self.session.wants_write() { - match self.write_io(cx) { - Poll::Ready(Ok(n)) => { - wrlen += n; - need_flush = true; - } - Poll::Pending => { - write_would_block = true; - break; - } - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - } - } - - if need_flush { - match Pin::new(&mut self.io).poll_flush(cx) { - Poll::Ready(Ok(())) => (), - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Pending => write_would_block = true, - } - } - - while !self.eof && self.session.wants_read() { - match self.read_io(cx) { - Poll::Ready(Ok(0)) => self.eof = true, - Poll::Ready(Ok(n)) => rdlen += n, - Poll::Pending => { - read_would_block = true; - break; - } - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - } - } - - return match (self.eof, self.session.is_handshaking()) { - (true, true) => { - let err = io::Error::new(io::ErrorKind::UnexpectedEof, "tls handshake eof"); - Poll::Ready(Err(err)) - } - (_, false) => Poll::Ready(Ok((rdlen, wrlen))), - (_, true) if write_would_block || read_would_block => { - if rdlen != 0 || wrlen != 0 { - Poll::Ready(Ok((rdlen, wrlen))) - } else { - Poll::Pending - } - } - (..) => continue, - }; - } - } -} - -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, C, SD> AsyncRead for Stream<'a, IO, C> -where - C: DerefMut + Deref>, - SD: SideData, -{ - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { - let mut io_pending = false; - - // read a packet - while !self.eof && self.session.wants_read() { - match self.read_io(cx) { - Poll::Ready(Ok(0)) => { - break; - } - Poll::Ready(Ok(_)) => (), - Poll::Pending => { - io_pending = true; - break; - } - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - } - } - - match self.session.reader().read(buf) { - Ok(n) => Poll::Ready(Ok(n)), - Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => { - if !io_pending { - cx.waker().wake_by_ref(); - } - Poll::Pending - } - - Err(err) => Poll::Ready(Err(err)), - } - } -} - -impl<'a, IO: AsyncRead + AsyncWrite + Unpin, C, SD> AsyncWrite for Stream<'a, IO, C> -where - C: DerefMut + Deref>, - SD: SideData, -{ - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context, - buf: &[u8], - ) -> Poll> { - let mut pos = 0; - - while pos != buf.len() { - let mut would_block = false; - - match self.session.writer().write(&buf[pos..]) { - Ok(n) => pos += n, - Err(err) => return Poll::Ready(Err(err)), - }; - - while self.session.wants_write() { - match self.write_io(cx) { - Poll::Ready(Ok(0)) | Poll::Pending => { - would_block = true; - break; - } - Poll::Ready(Ok(_)) => (), - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - } - } - - return match (pos, would_block) { - (0, true) => Poll::Pending, - (n, true) => Poll::Ready(Ok(n)), - (_, false) => continue, - }; - } - - Poll::Ready(Ok(pos)) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - self.session.writer().flush()?; - while self.session.wants_write() { - ready!(self.write_io(cx))?; - } - Pin::new(&mut self.io).poll_flush(cx) - } - - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - while self.session.wants_write() { - ready!(self.write_io(cx))?; - } - Pin::new(&mut self.io).poll_close(cx) - } -} - -/// An adapter that implements a [`Read`] interface for [`AsyncRead`] types and an -/// associated [`Context`]. -/// -/// Turns `Poll::Pending` into `WouldBlock`. -pub struct SyncReadAdapter<'a, 'b, T> { - pub io: &'a mut T, - pub cx: &'a mut Context<'b>, -} - -impl<'a, 'b, T: AsyncRead + Unpin> Read for SyncReadAdapter<'a, 'b, T> { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match Pin::new(&mut self.io).poll_read(self.cx, buf) { - Poll::Ready(Ok(n)) => Ok(n), - Poll::Ready(Err(err)) => Err(err), - Poll::Pending => Err(io::ErrorKind::WouldBlock.into()), - } - } -} - -/// An adapter that implements a [`Write`] interface for [`AsyncWrite`] types and an -/// associated [`Context`]. -pub struct SyncWriteAdapter<'a, 'b, T> { - pub(crate) io: &'a mut T, - pub(crate) cx: &'a mut Context<'b>, -} - -impl<'a, 'b, T: Unpin> SyncWriteAdapter<'a, 'b, T> { - #[inline] - fn poll_with( - &mut self, - f: impl FnOnce(Pin<&mut T>, &mut Context<'_>) -> Poll>, - ) -> io::Result { - match f(Pin::new(&mut self.io), self.cx) { - Poll::Ready(result) => result, - Poll::Pending => Err(io::ErrorKind::WouldBlock.into()), - } - } -} - -impl<'a, 'b, T: AsyncWrite + Unpin> Write for SyncWriteAdapter<'a, 'b, T> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.poll_with(|io, cx| io.poll_write(cx, buf)) - } - - #[inline] - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.poll_with(|io, cx| io.poll_write_vectored(cx, bufs)) - } - - fn flush(&mut self) -> io::Result<()> { - self.poll_with(|io, cx| io.poll_flush(cx)) - } -} diff --git a/nex-sys/Cargo.toml b/nex-sys/Cargo.toml index 9e04938..a84d8e1 100644 --- a/nex-sys/Cargo.toml +++ b/nex-sys/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nex-sys" version.workspace = true -edition = "2021" +edition.workspace = true authors.workspace = true description = "Provides network-related system function and call support for nex. Used for low-level system interactions." repository = "https://github.com/shellrow/nex" @@ -11,10 +11,10 @@ categories = ["network-programming"] license = "MIT" [dependencies] -libc = "0.2" +libc = { workspace = true } [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.52.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", diff --git a/nex/Cargo.toml b/nex/Cargo.toml index b8c80a0..6922795 100644 --- a/nex/Cargo.toml +++ b/nex/Cargo.toml @@ -19,13 +19,12 @@ nex-packet-builder = { path = "../nex-packet-builder", version = "0.18.0" } [dev-dependencies] serde_json = "1.0" -async-io = "2.3" +async-io = { workspace = true } futures = "0.3" [features] pcap = ["nex-datalink/pcap"] serde = ["nex-core/serde", "nex-packet/serde", "nex-datalink/serde"] -tls = ["nex-socket/tls"] [[example]] name = "dump" @@ -75,8 +74,3 @@ path = "../examples/async_tcp_connect.rs" [[example]] name = "async_tcp_stream" path = "../examples/async_tcp_stream.rs" - -[[example]] -name = "tls_stream" -path = "../examples/tls_stream.rs" -required-features = ["tls"]