From bfd9385844f9529da7ca15c0f676fbe0b02bced2 Mon Sep 17 00:00:00 2001 From: Tochukwu Nkemdilim Date: Mon, 2 Jul 2018 16:19:48 +0100 Subject: [PATCH] Chore(Linux): Add Connect To WPA & WPA --- Cargo.toml | 1 + src/connectivity/mod.rs | 30 ++++---- src/connectivity/profile_network.rs | 16 ++-- src/connectivity/providers/linux.rs | 105 ++++++++++++++++++-------- src/connectivity/providers/windows.rs | 24 +++--- src/lib.rs | 2 +- src/main.rs | 11 +-- 7 files changed, 115 insertions(+), 74 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 260ec49..ea3ce22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Tochukwu Nkemdilim "] [dependencies] +tempfile = "3.0.2" diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 6bde318..27e4b15 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -1,30 +1,34 @@ -pub mod profile_network; mod handlers; -mod stubs; +pub mod profile_network; mod providers; +mod stubs; use std::{fmt, io}; -use std::string::FromUtf8Error; -pub trait Network { +pub trait Network: fmt::Debug { /// Makes an attempt to connect to a selected wireless network with password specified. fn connect(&self, password: &str) -> bool; } -// Improve upon this. -impl fmt::Debug for Network { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Network") - } -} - +#[derive(Debug)] pub enum NetworkType { WEP, WPA, WPA2, } -pub enum NetworkTypeParseError { - FromUtf8Error(FromUtf8Error), +#[derive(Debug)] +pub enum NetworkError { + // FromUtf8Error(FromUtf8Error), + SsidNotFound, + OsNotSupported, + IpAssignFailed, IoError(io::Error), + FailedToConnect(String), +} + +impl From for NetworkError { + fn from(error: io::Error) -> Self { + NetworkError::IoError(error) + } } diff --git a/src/connectivity/profile_network.rs b/src/connectivity/profile_network.rs index b50fedf..dab5ea0 100644 --- a/src/connectivity/profile_network.rs +++ b/src/connectivity/profile_network.rs @@ -1,6 +1,4 @@ -use connectivity::providers::{Machine}; -use connectivity::Network; -use std::io::{Error, ErrorKind}; +use connectivity::{providers::Machine, Network, NetworkError}; #[derive(Debug)] pub struct ProfileNetwork { @@ -9,18 +7,16 @@ pub struct ProfileNetwork { /// Profile Network handler responsible to connect to a wireless network. impl ProfileNetwork { - pub fn new(name: &str) -> Result { + pub fn new(name: &str) -> Result { if !(cfg!(target_os = "linux") || cfg!(target_os = "windows")) { - return Err(Error::new( - ErrorKind::Other, - "The Specified OS is not supported", - )); + return Err(NetworkError::OsNotSupported); } let handler = Machine::new(name)?; - return Ok(ProfileNetwork { + + Ok(ProfileNetwork { handler: Box::new(handler), - }); + }) } pub fn connect(&self, password: &str) -> bool { diff --git a/src/connectivity/providers/linux.rs b/src/connectivity/providers/linux.rs index 2606150..ee892af 100644 --- a/src/connectivity/providers/linux.rs +++ b/src/connectivity/providers/linux.rs @@ -1,71 +1,110 @@ -use connectivity::{Network, NetworkType, NetworkTypeParseError}; -use std::io; -use std::io::{Error, ErrorKind}; -use std::process::{Command, Output}; +extern crate tempfile; +use self::tempfile::NamedTempFile; +use connectivity::{Network, NetworkError, NetworkType}; +use std::process::{Command, Output}; +use std::{ + fs::File, io::{Error, Read, Write}, +}; + +#[derive(Debug)] pub struct Linux { pub name: String, pub network_type: NetworkType, } impl Linux { - pub fn new(name: String) -> Result { - match Linux::check_if_web_or_wpa(name.clone()) { + pub fn new(name: &str) -> Result { + match Linux::check_if_web_or_wpa(name.into()) { Ok(t) => match t { NetworkType::WEP => Ok(Linux { - name: name.clone(), + name: name.into(), network_type: NetworkType::WEP, }), _ => Ok(Linux { - name: name.clone(), + name: name.into(), network_type: NetworkType::WPA, }), }, - Err(_) => Err(Error::new(ErrorKind::Other, "Failed to parse")), // use the NetworkTypeParseError::IoError here + Err(err) => Err(err), } } /// Detects the network type of a given network. - fn check_if_web_or_wpa(name: String) -> Result { + fn check_if_web_or_wpa(name: String) -> Result { Command::new("nmcli") .args(&[ + "-t", + "-f", + "802-11-wireless-security.key-mgmt", "con", - "list", - "id", - "\"", + "show", &name, - "\"", - "|", - "awk", - "'/key-mgmt/ {{ print $2 }}'", ]) .output() - .map_err(|err| NetworkTypeParseError::IoError(err)) + .map_err(|err| NetworkError::IoError(err)) .and_then(|output| { - String::from_utf8(output.stdout) - .map_err(|err| NetworkTypeParseError::FromUtf8Error(err)) - .and_then(|result| match result.as_ref() { - "wpa-psk" => Ok(NetworkType::WPA), - _ => Ok(NetworkType::WEP), - }) + let output = String::from_utf8_lossy(&output.stdout); + let psk = { + let mut split = output.split(':'); + let _ = split.next(); + match split.next() { + Some(x) => x, + None => return Err(NetworkError::SsidNotFound), + } + }; + + match psk.trim() { + "wpa-psk" => Ok(NetworkType::WPA), + _ => Ok(NetworkType::WEP), + } }) } - pub fn connect_to_wep_network(&self, password: &str) -> Result { - Command::new("iwconfig") + pub fn connect_to_wep_network(&self, password: &str) -> Result { + Ok(Command::new("iwconfig") .args(&["wlan0", "essid", &self.name, "key", password]) .output() + .map_err(|err| NetworkError::FailedToConnect(format!("{:?}", err)))?) } - pub fn connect_to_wpa_network(&self, password: &str) -> Result { - // Dynamically generate differennt version of file (if running sync) - Command::new("wpa_passphrase") - .args(&[&self.name, password, "wpa.conf"]) + pub fn connect_to_wpa_network(&self, password: &str) -> Result { + let passphrase = Command::new("wpa_passphrase") + .args(&[&self.name, password]) .output()?; - Ok(Command::new("wpa_supplicant") - .args(&["-Dwext", "-i", "wlan0", "-c/root/wpa.conf"]) - .output()?) + let wpa_conf_file = self.create_conf_file(&String::from_utf8_lossy(&passphrase.stdout))?; + + let mut file = File::open(wpa_conf_file.path())?; + let mut new_content = String::new(); + file.read_to_string(&mut new_content)?; + + Command::new("wpa_supplicant") + .args(&[ + "-D", + "wext", + "-B", + "-i", + "wlo1", + wpa_conf_file.path().to_str().unwrap(), + ]) + .output() + .map_err(|err| NetworkError::FailedToConnect(format!("{:?}", err)))?; + + let a = Command::new("dhclient").args(&["wlo1"]).output()?; + println!("{:?}", String::from_utf8_lossy(&a.stdout)); + + Ok(Command::new("dhclient") + .args(&["wlo1"]) + .output() + .map_err(|_| NetworkError::IpAssignFailed)?) + } + + fn create_conf_file(&self, content: &str) -> Result { + let mut temp_file = NamedTempFile::new()?; + write!(temp_file, "{}", content)?; + + Ok(temp_file) } } diff --git a/src/connectivity/providers/windows.rs b/src/connectivity/providers/windows.rs index af18d04..ca6b41e 100644 --- a/src/connectivity/providers/windows.rs +++ b/src/connectivity/providers/windows.rs @@ -1,17 +1,16 @@ use connectivity::handlers::NetworkXmlProfileHandler; use connectivity::Network; -use std::io; + use std::process::Command; -const OUTPUT_XML_FILE_PATH: &str = "output.xml"; - -#[cfg(target_os = "windows")] +#[derive(Debug)] pub(crate) struct Windows { name: String, pub output_xml_path: String, } impl Windows { + #[cfg(target_os = "windows")] pub fn new(name: &str) -> Result { Ok(Windows { name: String::from(name), @@ -33,12 +32,17 @@ impl Windows { // Add the network profile if let Err(_) = Command::new("netsh") - .args(&["wlan", "add", "profile", &format!("filename={}", self.output_xml_path)]) + .args(&[ + "wlan", + "add", + "profile", + &format!("filename={}", self.output_xml_path), + ]) .output() - { - return false; - } - + { + return false; + } + true } } @@ -48,7 +52,7 @@ impl Network for Windows { if self.add_profile(password) == false { return false; } - + let output = Command::new("netsh") .args(&["wlan", "connect", &format!("name={}", self.name)]) .output(); diff --git a/src/lib.rs b/src/lib.rs index a7d8e82..6896143 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] mod connectivity; -pub use connectivity::profile_network::ProfileNetwork as WiFi; +pub use connectivity::{profile_network::ProfileNetwork as WiFi, *}; #[cfg(test)] mod tests { diff --git a/src/main.rs b/src/main.rs index f4dc9b6..60be885 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,9 @@ -use std::io; mod connectivity; -pub use connectivity::profile_network::ProfileNetwork as WiFi; - - -fn main() -> Result<(), io::Error> { - let mut wifi = WiFi::new("AndroidAPS")?; +pub use connectivity::{profile_network::ProfileNetwork as WiFi, NetworkError}; +fn main() -> Result<(), NetworkError> { + let wifi = WiFi::new("AndroidAPSD")?; println!("{}", wifi.connect("belm4235")); Ok(()) -} \ No newline at end of file +}