diff --git a/Cargo.lock b/Cargo.lock index 6d39d43..abad00b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2638,7 +2638,6 @@ dependencies = [ "regex", "serde 1.0.130", "serde_json", - "snafu 0.6.10", "wpactrl", ] diff --git a/peach-network/Cargo.toml b/peach-network/Cargo.toml index aa81ab9..cc2eead 100644 --- a/peach-network/Cargo.toml +++ b/peach-network/Cargo.toml @@ -36,7 +36,6 @@ log = "0.4" probes = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" -snafu = "0.6" regex = "1" wpactrl = "0.3.1" diff --git a/peach-network/src/error.rs b/peach-network/src/error.rs index 808f208..c332b0f 100644 --- a/peach-network/src/error.rs +++ b/peach-network/src/error.rs @@ -1,150 +1,293 @@ use std::{error, io, str}; -use jsonrpc_core::{types::error::Error, ErrorCode}; +use jsonrpc_core::{types::error::Error as JsonRpcError, ErrorCode}; use probes::ProbeError; use serde_json::error::Error as SerdeError; -use snafu::Snafu; -pub type BoxError = Box; - -#[derive(Debug, Snafu)] -#[snafu(visibility(pub(crate)))] +#[derive(Debug)] pub enum NetworkError { - #[snafu(display("{}", err_msg))] - ActivateAp { err_msg: String }, + Add { + ssid: String, + }, - #[snafu(display("{}", err_msg))] - ActivateClient { err_msg: String }, + NoState { + iface: String, + source: io::Error, + }, - #[snafu(display("Failed to add network for {}", ssid))] - Add { ssid: String }, + Disable { + id: String, + iface: String, + }, - #[snafu(display("Failed to retrieve state for interface: {}", iface))] - NoState { iface: String, source: io::Error }, + Disconnect { + iface: String, + }, - #[snafu(display("Failed to disable network {} for interface: {}", id, iface))] - Disable { id: String, iface: String }, + GenWpaPassphrase { + ssid: String, + source: io::Error, + }, - #[snafu(display("Failed to disconnect {}", iface))] - Disconnect { iface: String }, + GenWpaPassphraseWarning { + ssid: String, + err_msg: String, + }, - #[snafu(display("Failed to generate wpa passphrase for {}: {}", ssid, source))] - GenWpaPassphrase { ssid: String, source: io::Error }, + Id { + ssid: String, + iface: String, + }, - #[snafu(display("Failed to generate wpa passphrase for {}: {}", ssid, err_msg))] - GenWpaPassphraseWarning { ssid: String, err_msg: String }, + NoIp { + iface: String, + source: io::Error, + }, - #[snafu(display("No ID found for {} on interface: {}", ssid, iface))] - Id { ssid: String, iface: String }, + Rssi { + iface: String, + }, - #[snafu(display("Could not access IP address for interface: {}", iface))] - NoIp { iface: String, source: io::Error }, + RssiPercent { + iface: String, + }, - #[snafu(display("Could not find RSSI for interface: {}", iface))] - Rssi { iface: String }, + Ssid { + iface: String, + }, - #[snafu(display("Could not find signal quality (%) for interface: {}", iface))] - RssiPercent { iface: String }, + State { + iface: String, + }, - #[snafu(display("Could not find SSID for interface: {}", iface))] - Ssid { iface: String }, + Status { + iface: String, + }, - #[snafu(display("No state found for interface: {}", iface))] - State { iface: String }, + Traffic { + iface: String, + }, - #[snafu(display("No status found for interface: {}", iface))] - Status { iface: String }, - - #[snafu(display("Could not find network traffic for interface: {}", iface))] - Traffic { iface: String }, - - #[snafu(display("No saved networks found for default interface"))] SavedNetworks, - #[snafu(display("No networks found in range of interface: {}", iface))] - AvailableNetworks { iface: String }, + AvailableNetworks { + iface: String, + }, - #[snafu(display("Missing expected parameters: {}", e))] - MissingParams { e: Error }, + MissingParams(JsonRpcError), - #[snafu(display("Failed to set new password for network {} on {}", id, iface))] - Modify { id: String, iface: String }, + Modify { + id: String, + iface: String, + }, - #[snafu(display("No IP found for interface: {}", iface))] - Ip { iface: String }, + Ip { + iface: String, + }, - #[snafu(display("Failed to parse integer from string for RSSI value: {}", source))] - ParseString { source: std::num::ParseIntError }, + ParseString(std::num::ParseIntError), - #[snafu(display( - "Failed to retrieve network traffic measurement for {}: {}", - iface, - source - ))] - NoTraffic { iface: String, source: ProbeError }, + NoTraffic { + iface: String, + source: ProbeError, + }, - #[snafu(display("Failed to reassociate with WiFi network for interface: {}", iface))] - Reassociate { iface: String }, + Reassociate { + iface: String, + }, - #[snafu(display("Failed to force reread of wpa_supplicant configuration file"))] Reconfigure, - #[snafu(display("Failed to reconnect with WiFi network for interface: {}", iface))] - Reconnect { iface: String }, + Reconnect { + iface: String, + }, - #[snafu(display("Regex command failed"))] - Regex { source: regex::Error }, + Regex(regex::Error), - #[snafu(display("Failed to delete network {} for interface: {}", id, iface))] - Delete { id: String, iface: String }, + Delete { + id: String, + iface: String, + }, - #[snafu(display("Failed to retrieve state of wlan0 service: {}", source))] - WlanState { source: io::Error }, + WlanState(io::Error), - #[snafu(display("Failed to retrieve connection state of wlan0 interface: {}", source))] - WlanOperstate { source: io::Error }, + WlanOperstate(io::Error), - #[snafu(display("Failed to save configuration changes to file"))] Save, - #[snafu(display("Failed to connect to network {} for interface: {}", id, iface))] - Connect { id: String, iface: String }, - - #[snafu(display("Failed to start ap0 service: {}", source))] - StartAp0 { source: io::Error }, - - #[snafu(display("Failed to start wlan0 service: {}", source))] - StartWlan0 { source: io::Error }, - - #[snafu(display("JSON serialization failed: {}", source))] - SerdeSerialize { source: SerdeError }, - - #[snafu(display("Failed to open control interface for wpasupplicant"))] - WpaCtrlOpen { - #[snafu(source(from(failure::Error, std::convert::Into::into)))] - source: BoxError, + Connect { + id: String, + iface: String, }, - #[snafu(display("Request to wpasupplicant via wpactrl failed"))] - WpaCtrlRequest { - #[snafu(source(from(failure::Error, std::convert::Into::into)))] - source: BoxError, - }, + StartAp0(io::Error), + + StartWlan0(io::Error), + + SerdeSerialize(SerdeError), + + WpaCtrlOpen(failure::Error), + + WpaCtrlRequest(failure::Error), +} + +impl std::error::Error for NetworkError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + NetworkError::Add { .. } => None, + NetworkError::NoState { .., ref source } => Some(source), + NetworkError::Disable { .. } => None, + NetworkError::Disconnect { .. } => None, + NetworkError::GenWpaPassphrase { .., ref source } => Some(source), + NetworkError::GenWpaPassphraseWarning { .. } => None, + NetworkError::Id { .. } => None, + NetworkError::NoIp { .., ref source } => Some(source), + NetworkError::Rssi { .. } => None, + NetworkError::RssiPercent { .. } => None, + NetworkError::Ssid { .. } => None, + NetworkError::State { .. } => None, + NetworkError::Status { .. } => None, + NetworkError::Traffic { .. } => None, + NetworkError::SavedNetworks => None, + NetworkError::AvailableNetworks { .. } => None, + NetworkError::MissingParams(ref source) => Some(source), + NetworkError::Modify { .. } => None, + NetworkError::Ip { .. } => None, + NetworkError::ParseString(ref source) => Some(source), + NetworkError::NoTraffic { .., ref source } => Some(source), + NetworkError::Reassociate { .. } => None, + NetworkError::Reconfigure { .. } => None, + NetworkError::Reconnect { .. } => None, + NetworkError::Regex(ref source) => Some(source), + NetworkError::Delete { .. } => None, + NetworkError::WpaState(ref source) => Some(source), + NetworkError::WpaOperstate(ref source) => Some(source), + NetworkError::Save => None, + NetworkError::Connect { .. } => None, + NetworkError::StartWlan0(ref source) => Some(source), + NetworkError::StartAp0(ref source) => Some(source), + NetworkError::SerdeSerialize(ref source) => Some(source), + NetworkError::WpaCtrlOpen(ref source) => Some(source), + NetworkError::WpaCtrlRequest(ref source) => Some(source), + } + } +} + +impl std::fmt::Display for NetworkError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match *self { + NetworkError::Add { ref ssid } => { + write!(f, "Failed to add network for {}", ssid) + }, + NetworkError::NoState { ref iface, .. } => { + write!(f, "Failed to retrieve state for interface: {}", iface) + }, + NetworkError::Disable { ref id, ref iface } => { + write!(f, "Failed to disable network {} for interface: {}", id, iface) + }, + NetworkError::Disconnect { ref iface } => { + write!(f, "Failed to disconnect {}", iface) + }, + NetworkError::GenWpaPassphrase { ref ssid, .. } => { + write!(f, "Failed to generate wpa passphrase for {}", ssid) + }, + NetworkError::GenWpaPassphraseWarning { ref ssid, ref err_msg } => { + write!(f, "Failed to generate wpa passphrase for {}: {}", ssid, err_msg) + }, + NetworkError::Id { ref ssid, ref iface } => { + write!(f, "No ID found for {} on interface: {}: {}", ssid, iface) + }, + NetworkError::NoIp { ref iface, .. } => { + write!(f, "Could not access IP address for interface: {}", iface) + }, + NetworkError::Rssi { ref iface } => { + write!(f, "Could not find RSSI for interface: {}", iface) + }, + NetworkError::RssiPercent { ref iface } => { + write!(f, "Could not find signal quality (%) for interface: {}", iface) + }, + NetworkError::Ssid { ref iface } => { + write!(f, "Could not find SSID for interface: {}", iface) + }, + NetworkError::State { ref iface } => { + write!(f, "No state found for interface: {}", iface) + }, + NetworkError::Status { ref iface } => { + write!(f, "No status found for interface: {}", iface) + }, + NetworkError::Traffic { ref iface } => { + write!(f, "Could not find network traffice for interface: {}", iface) + }, + NetworkError::SavedNetworks => { + write!("No saved networks found for default interface") + }, + NetworkError::AvailableNetworks { ref iface } => { + write!(f, "No networks found in range of interface: {}", iface) + }, + NetworkError::MissingParams(ref source) => { + write!(f, "Missing expected parameters: {}", source) + }, + NetworkError::Modify { ref id, ref iface } => { + write!(f, "Failed to set new password for network {} on {}", id, iface) + }, + NetworkError::Ip { ref iface } => { + write!(f, "No IP found for interface: {}", iface) + }, + NetworkError::ParseString(_) => { + write!("Failed to parse integer from string for RSSI value") + }, + NetworkError::NoTraffic { ref id, .. } => { + write!("Failed to retrieve network traffic measurement for {}", id) + }, + NetworkError::Reassociate { ref iface } => { + write!(f, "Failed to reassociate with WiFi network for interface: {}", iface) + }, + NetworkError::Reconfigure => { + write!("Failed to force reread of wpa_supplicant configuration file") + }, + NetworkError::Reconnect { ref iface } => { + write!(f, "Failed to reconnect with WiFi network for interface: {}", iface) + }, + NetworkError::Regex(_) => { + write!("Regex command failed") + }, + NetworkError::Delete { ref id, ref iface } => { + write!(f, "Failed to delete network {} for interface: {}", id, iface) + }, + NetworkError::WpaState(_) => { + write!("Failed to retrieve state of wlan0 service") + }, + NetworkError::WpaOperstate(_) => { + write!("Failed to retrieve connection state of wlan0 interface") + }, + NetworkError::Save => { + write!("Failed to save configuration changes to file") + }, + NetworkError::Connect { ref id, ref iface } => { + write!(f, "Failed to connect to network {} for interface: {}", id, iface) + }, + NetworkError::StartWlan0(_) => { + write!("Failed to start ap0 service") + }, + NetworkError::StartAp0(_) => { + write!("Failed to start wlan0 service") + }, + NetworkError::SerdeSerialize(_) => { + write!("JSON serialization failed") + }, + NetworkError::WpaCtrlOpen(_) => { + write!("Failed to open control interface for wpasupplicant") + }, + NetworkError::WpaCtrlRequest(_) => { + write!("Request to wpasupplicant via wpactrl failed") + }, + } + } } impl From for Error { fn from(err: NetworkError) -> Self { match &err { - NetworkError::ActivateAp { err_msg } => Error { - code: ErrorCode::ServerError(-32015), - message: err_msg.to_string(), - data: None, - }, - NetworkError::ActivateClient { err_msg } => Error { - code: ErrorCode::ServerError(-32017), - message: err_msg.to_string(), - data: None, - }, NetworkError::Add { ssid } => Error { code: ErrorCode::ServerError(-32000), message: format!("Failed to add network for {}", ssid), @@ -243,7 +386,7 @@ impl From for Error { message: format!("No networks found in range of {}", iface), data: None, }, - NetworkError::MissingParams { e } => e.clone(), + NetworkError::MissingParams(e) => e.clone(), NetworkError::Modify { id, iface } => Error { code: ErrorCode::ServerError(-32033), message: format!("Failed to set new password for network {} on {}", id, iface), diff --git a/peach-network/src/lib.rs b/peach-network/src/lib.rs index 2872b27..88155f0 100644 --- a/peach-network/src/lib.rs +++ b/peach-network/src/lib.rs @@ -317,7 +317,7 @@ pub fn run() -> Result<(), BoxError> { Err(_) => Err(Error::from(NetworkError::Connect { id, iface })), } } - Err(e) => Err(Error::from(NetworkError::MissingParams { e })), + Err(e) => Err(Error::from(NetworkError::MissingParams(e))), } }); diff --git a/peach-network/src/network.rs b/peach-network/src/network.rs index e52c1b2..6373a3b 100644 --- a/peach-network/src/network.rs +++ b/peach-network/src/network.rs @@ -21,13 +21,9 @@ use std::{ str, }; -use crate::error::{ - GenWpaPassphrase, NetworkError, NoIp, NoState, NoTraffic, ParseString, SerdeSerialize, - StartAp0, StartWlan0, WlanState, WpaCtrlOpen, WpaCtrlRequest, -}; +use crate::error::NetworkError; use probes::network; use serde::{Deserialize, Serialize}; -use snafu::ResultExt; use crate::utils; @@ -122,6 +118,14 @@ pub struct WiFi { pub pass: String, } +// TODO: wrap this into a helper function: +// +// let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface); +// let mut wpa = wpactrl::WpaCtrl::new() +// .ctrl_path(wpa_path) +// .open() +// .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; + /* GET - Methods for retrieving data */ /// Retrieve list of available wireless access points for a given network @@ -145,8 +149,9 @@ pub fn available_networks(iface: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; - wpa.request("SCAN").context(WpaCtrlRequest)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; + wpa.request("SCAN") + .map_err(|source| NetworkError::WpaCtrlRequest(source.compat()))?; let networks = wpa.request("SCAN_RESULTS").context(WpaCtrlRequest)?; let mut scan = Vec::new(); for network in networks.lines() { @@ -204,8 +209,10 @@ pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; - let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; + let networks = wpa + .request("LIST_NETWORKS") + .map_err(|source| NetworkError::WpaCtrlRequest(source.compat()))?; let mut id = Vec::new(); for network in networks.lines() { let v: Vec<&str> = network.split('\t').collect(); @@ -239,7 +246,7 @@ pub fn id(iface: &str, ssid: &str) -> Result, NetworkError> { /// pub fn ip(iface: &str) -> Result, NetworkError> { let net_if: String = iface.to_string(); - let ifaces = get_if_addrs::get_if_addrs().context(NoIp { iface: net_if })?; + let ifaces = get_if_addrs::get_if_addrs().map_err(|_| NetworkError::NoIp { iface: net_if })?; let ip = ifaces .iter() .find(|&i| i.name == iface) @@ -268,7 +275,7 @@ pub fn rssi(iface: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?; let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?; @@ -300,7 +307,7 @@ pub fn rssi_percent(iface: &str) -> Result, NetworkError> { let mut wpa = wpactrl::WpaCtrl::new() .ctrl_path(wpa_path) .open() - .context(WpaCtrlOpen)?; + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?; let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?; @@ -335,7 +342,9 @@ pub fn rssi_percent(iface: &str) -> Result, NetworkError> { /// sent to the caller. /// pub fn saved_networks() -> Result, NetworkError> { - let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?; + let mut wpa = wpactrl::WpaCtrl::new() + .open() + .map_err(|source| NetworkError::WpaCtrlOpen(source.compat()))?; let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?; let mut ssids = Vec::new(); for network in networks.lines() {