use super::sys;
use privilege::runas::Command as RunasCommand;
use sha2::{Digest, Sha256};
use std::error::Error;
use std::fs::File;
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";
pub fn npcap_installed() -> bool {
sys::software_installed(NPCAP_SOFTWARE_NAME.to_owned())
}
pub fn npcap_sdk_installed() -> bool {
let env_lib_value: String = sys::get_env_lib();
if env_lib_value.is_empty() {
return false;
}
let lib_path_list: Vec<&str> = env_lib_value.split(";").collect();
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")]
pub fn install_npcap() -> Result<(), Box<dyn Error>> {
let npcap_installer_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_INSTALLER_FILENAME);
let install_dir: String = sys::get_install_path(NPCAP_INSTALL_DIR_NAME);
if !std::path::Path::new(&install_dir).exists() {
std::fs::create_dir_all(&install_dir)?;
}
let npcap_target_path: String = format!(
"{}\\{}",
sys::get_install_path(NPCAP_INSTALL_DIR_NAME),
NPCAP_INSTALLER_FILENAME
);
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)?;
std::thread::sleep(std::time::Duration::from_secs(10));
}
let mut file: File = File::open(&npcap_target_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());
}
let exit_status: std::process::ExitStatus = RunasCommand::new(&npcap_target_path)
.arg("/loopback_support=yes")
.arg("/winpcap_mode=yes")
.run()?;
if !exit_status.success() {
return Err("Error: Npcap installation failed !".into());
}
std::fs::remove_file(&npcap_target_path)?;
Ok(())
}
#[cfg(feature = "download")]
pub fn download_npcap(dst_dir_path: String) -> Result<(), Box<dyn Error>> {
let npcap_installer_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_INSTALLER_FILENAME);
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);
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(())
}
pub fn verify_installer_checksum(file_path: String) -> Result<(), Box<dyn Error>> {
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(())
}
pub fn run_npcap_installer(file_path: String) -> Result<(), Box<dyn Error>> {
if !std::path::Path::new(&file_path).exists() {
return Err("Error: file not found...".into());
}
verify_installer_checksum(file_path.clone())?;
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")]
pub fn install_npcap_sdk() -> Result<(), Box<dyn Error>> {
let npcap_sdk_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_SDK_FILENAME);
let install_dir: String = sys::get_install_path(NPCAP_INSTALL_DIR_NAME);
if !std::path::Path::new(&install_dir).exists() {
std::fs::create_dir_all(&install_dir)?;
}
let npcap_sdk_target_path: String = format!(
"{}\\{}",
sys::get_install_path(NPCAP_INSTALL_DIR_NAME),
NPCAP_SDK_FILENAME
);
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)?;
}
let mut file: File = File::open(&npcap_sdk_target_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());
}
let npcap_sdk_extract_dir: String = format!(
"{}\\{}",
sys::get_install_path(NPCAP_INSTALL_DIR_NAME),
NPCAP_SDK_DIR_NAME
);
let mut archive: zip::ZipArchive<File> =
zip::ZipArchive::new(File::open(&npcap_sdk_target_path)?)?;
for i in 0..archive.len() {
let mut file: zip::read::ZipFile = archive.by_index(i)?;
let outpath: std::path::PathBuf =
format!("{}\\{}", npcap_sdk_extract_dir, file.name()).into();
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)?;
}
}
let os_bit: String = sys::get_os_bit();
let lib_dir_path: String = if os_bit == "32-bit" {
format!("{}\\{}", npcap_sdk_extract_dir, "Lib")
} else {
format!("{}\\{}", npcap_sdk_extract_dir, "Lib\\x64")
};
if !sys::check_env_lib_path(&lib_dir_path) {
match sys::add_env_lib_path(&lib_dir_path) {
Ok(_) => {}
Err(e) => Err(e)?,
}
}
std::fs::remove_file(&npcap_sdk_target_path)?;
Ok(())
}
#[cfg(feature = "download")]
pub fn download_npcap_sdk(dst_dir_path: String) -> Result<(), Box<dyn Error>> {
let npcap_sdk_url = format!("{}{}", NPCAP_DIST_BASE_URL, NPCAP_SDK_FILENAME);
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);
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(())
}
pub fn verify_sdk_checksum(file_path: String) -> Result<(), Box<dyn Error>> {
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(())
}
pub fn extract_npcap_sdk(file_path: String) -> Result<(), Box<dyn Error>> {
if !std::path::Path::new(&file_path).exists() {
return Err("Error: file not found...".into());
}
verify_sdk_checksum(file_path.clone())?;
let npcap_sdk_extract_dir: String = format!(
"{}\\{}",
sys::get_install_path(NPCAP_INSTALL_DIR_NAME),
NPCAP_SDK_DIR_NAME
);
let mut archive: zip::ZipArchive<File> = 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 =
format!("{}\\{}", npcap_sdk_extract_dir, file.name()).into();
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(())
}
pub fn add_npcap_sdk_to_lib(lib_dir_path: String) -> Result<(), Box<dyn Error>> {
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) {
match sys::add_env_lib_path(&lib_dir_path) {
Ok(_) => {}
Err(e) => Err(e)?,
}
}
Ok(())
}