Merge pull request 'Removed hardcoded interfaces from peach-network' (#47) from iface_agnostic into main

Reviewed-on: #47
This commit is contained in:
glyph 2021-12-14 20:42:40 +00:00
commit b5ce677a5b
5 changed files with 52 additions and 57 deletions

2
Cargo.lock generated
View File

@ -2532,7 +2532,7 @@ dependencies = [
[[package]] [[package]]
name = "peach-network" name = "peach-network"
version = "0.3.0" version = "0.4.0"
dependencies = [ dependencies = [
"get_if_addrs", "get_if_addrs",
"miniserde", "miniserde",

View File

@ -1,8 +1,8 @@
[package] [package]
name = "peach-network" name = "peach-network"
version = "0.3.0" version = "0.4.0"
authors = ["Andrew Reid <glyph@mycelial.technology>"] authors = ["Andrew Reid <glyph@mycelial.technology>"]
edition = "2018" edition = "2021"
description = "Query and configure network interfaces." description = "Query and configure network interfaces."
homepage = "https://opencollective.com/peachcloud" homepage = "https://opencollective.com/peachcloud"
repository = "ihttps://git.coopcloud.tech/PeachCloud/peach-workspace/src/branch/main/peach-network" repository = "ihttps://git.coopcloud.tech/PeachCloud/peach-workspace/src/branch/main/peach-network"

View File

@ -1,6 +1,6 @@
# peach-network # peach-network
![Generic badge](https://img.shields.io/badge/version-0.3.0-<COLOR>.svg) ![Generic badge](https://img.shields.io/badge/version-0.4.0-<COLOR>.svg)
Network interface state query and modification library. Network interface state query and modification library.

View File

@ -156,10 +156,13 @@ pub enum NetworkError {
/// Interface. /// Interface.
iface: String, iface: String,
}, },
/// Failed to start ap0 service. /// Failed to start systemctl service for a network interface.
StartAp0(IoError), StartInterface {
/// Failed to start wlan0 service. /// Underlying error source.
StartWlan0(IoError), source: IoError,
/// Interface.
iface: String,
},
/// Failed to execute wpa-ctrl command. /// Failed to execute wpa-ctrl command.
WpaCtrl(WpaError), WpaCtrl(WpaError),
} }
@ -196,8 +199,7 @@ impl std::error::Error for NetworkError {
NetworkError::WlanOperstate(ref source) => Some(source), NetworkError::WlanOperstate(ref source) => Some(source),
NetworkError::Save => None, NetworkError::Save => None,
NetworkError::Connect { .. } => None, NetworkError::Connect { .. } => None,
NetworkError::StartWlan0(ref source) => Some(source), NetworkError::StartInterface { ref source, .. } => Some(source),
NetworkError::StartAp0(ref source) => Some(source),
NetworkError::WpaCtrl(ref source) => Some(source), NetworkError::WpaCtrl(ref source) => Some(source),
} }
} }
@ -332,8 +334,11 @@ impl std::fmt::Display for NetworkError {
id, iface id, iface
) )
} }
NetworkError::StartWlan0(_) => write!(f, "Failed to start ap0 service"), NetworkError::StartInterface { ref iface, .. } => write!(
NetworkError::StartAp0(_) => write!(f, "Failed to start wlan0 service"), f,
"Failed to start systemctl service for {} interface",
iface
),
NetworkError::WpaCtrl(_) => write!(f, "WpaCtrl command failed"), NetworkError::WpaCtrl(_) => write!(f, "WpaCtrl command failed"),
} }
} }

View File

@ -11,7 +11,7 @@
//! Switching between client mode and access point mode is achieved by making //! Switching between client mode and access point mode is achieved by making
//! system calls to systemd (via `systemctl`). Further networking functionality //! system calls to systemd (via `systemctl`). Further networking functionality
//! is provided by making system calls to retrieve interface state and write //! is provided by making system calls to retrieve interface state and write
//! access point credentials to `wpa_supplicant-wlan0.conf`. //! access point credentials to `wpa_supplicant-<wlan_iface>.conf`.
use std::{ use std::{
fs::OpenOptions, fs::OpenOptions,
@ -478,36 +478,22 @@ pub fn traffic(iface: &str) -> Result<Option<Traffic>, NetworkError> {
/* SET - Methods for modifying state */ /* SET - Methods for modifying state */
/// Activate wireless access point. /// Start network interface service.
/// ///
/// A `systemctl `command is invoked which starts the `ap0` interface service. /// A `systemctl `command is invoked which starts the service for the given
/// If the command executes successfully, an `Ok` `Result` type is returned. /// network interface. If the command executes successfully, an `Ok` `Result`
/// In the event of an error, a `NetworkError` is returned in the `Result`. /// type is returned. In the event of an error, a `NetworkError` is returned
pub fn activate_ap() -> Result<(), NetworkError> { /// in the `Result`.
// start the ap0 interface service pub fn start_iface_service(iface: String) -> Result<(), NetworkError> {
let iface_service = format!("wpa_supplicant@{}.service", &iface);
// start the interface service
Command::new("sudo") Command::new("sudo")
.arg("/usr/bin/systemctl") .arg("/usr/bin/systemctl")
.arg("start") .arg("start")
.arg("wpa_supplicant@ap0.service") .arg(iface_service)
.output() .output()
.map_err(NetworkError::StartAp0)?; .map_err(|source| NetworkError::StartInterface { source, iface })?;
Ok(())
}
/// Activate wireless client.
///
/// A `systemctl` command is invoked which starts the `wlan0` interface service.
/// If the command executes successfully, an `Ok` `Result` type is returned.
/// In the event of an error, a `NetworkError` is returned in the `Result`.
pub fn activate_client() -> Result<(), NetworkError> {
// start the wlan0 interface service
Command::new("sudo")
.arg("/usr/bin/systemctl")
.arg("start")
.arg("wpa_supplicant@wlan0.service")
.output()
.map_err(NetworkError::StartWlan0)?;
Ok(()) Ok(())
} }
@ -516,13 +502,15 @@ pub fn activate_client() -> Result<(), NetworkError> {
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `wlan_iface` - A local wireless interface.
/// * `wifi` - An instance of the `WiFi` `struct` with fields `ssid` and `pass` /// * `wifi` - An instance of the `WiFi` `struct` with fields `ssid` and `pass`
/// ///
/// If configuration parameters are successfully generated from the provided /// If configuration parameters are successfully generated from the provided
/// SSID and password and appended to `wpa_supplicant-wlan0.conf`, an `Ok` /// SSID and password and appended to `wpa_supplicant-<wlan_iface>.conf` (where
/// `Result` type is returned. In the event of an error, a `NetworkError` is /// `<wlan_iface>` is the provided interface parameter), an `Ok` `Result` type
/// returned in the `Result`. /// is returned. In the event of an error, a `NetworkError` is returned in the
pub fn add(wifi: &WiFi) -> Result<(), NetworkError> { /// `Result`.
pub fn add(wlan_iface: String, wifi: &WiFi) -> Result<(), NetworkError> {
// generate configuration based on provided ssid & password // generate configuration based on provided ssid & password
let output = Command::new("wpa_passphrase") let output = Command::new("wpa_passphrase")
.arg(&wifi.ssid) .arg(&wifi.ssid)
@ -538,12 +526,12 @@ pub fn add(wifi: &WiFi) -> Result<(), NetworkError> {
let mut wpa_details = "\n".as_bytes().to_vec(); let mut wpa_details = "\n".as_bytes().to_vec();
wpa_details.extend(&*(output.stdout)); wpa_details.extend(&*(output.stdout));
// append wpa_passphrase output to wpa_supplicant-wlan0.conf if successful let wlan_config = format!("/etc/wpa_supplicant/wpa_supplicant-{}.conf", wlan_iface);
// append wpa_passphrase output to wpa_supplicant-<wlan_iface>.conf if successful
if output.status.success() { if output.status.success() {
// open file in append mode // open file in append mode
let file = OpenOptions::new() let file = OpenOptions::new().append(true).open(wlan_config);
.append(true)
.open("/etc/wpa_supplicant/wpa_supplicant-wlan0.conf");
let _file = match file { let _file = match file {
// if file exists & open succeeds, write wifi configuration // if file exists & open succeeds, write wifi configuration
@ -563,33 +551,35 @@ pub fn add(wifi: &WiFi) -> Result<(), NetworkError> {
} }
} }
/// Deploy the access point if the `wlan0` interface is `up` without an active /// Deploy an access point if the wireless interface is `up` without an active
/// connection. /// connection.
/// ///
/// The status of the `wlan0` service and the state of the `wlan0` interface /// The status of the wireless service and the state of the wireless interface
/// are checked. If the service is active but the interface is down (ie. not /// are checked. If the service is active but the interface is down (ie. not
/// currently connected to an access point), then the access point is activated /// currently connected to an access point), then the access point is activated
/// by calling the `activate_ap()` function. /// by calling the `activate_ap()` function.
pub fn check_iface() -> Result<(), NetworkError> { pub fn check_iface(wlan_iface: String, ap_iface: String) -> Result<(), NetworkError> {
let wpa_service = format!("wpa_supplicant@{}.service", &wlan_iface);
// returns 0 if the service is currently active // returns 0 if the service is currently active
let wlan0_status = Command::new("/usr/bin/systemctl") let wlan_status = Command::new("/usr/bin/systemctl")
.arg("is-active") .arg("is-active")
.arg("wpa_supplicant@wlan0.service") .arg(wpa_service)
.status() .status()
.map_err(NetworkError::WlanState)?; .map_err(NetworkError::WlanState)?;
// returns the current state of the wlan0 interface // returns the current state of the wlan interface
let iface_state = state("wlan0")?; let iface_state = state(&wlan_iface)?;
// returns down if the interface is not currently connected to an ap // returns down if the interface is not currently connected to an ap
let wlan0_state = match iface_state { let wlan_state = match iface_state {
Some(state) => state, Some(state) => state,
None => "error".to_string(), None => "error".to_string(),
}; };
// if wlan0 is active but not connected, start the ap0 service // if wlan is active but not connected, start the ap service
if wlan0_status.success() && wlan0_state == "down" { if wlan_status.success() && wlan_state == "down" {
activate_ap()? start_iface_service(ap_iface)?
} }
Ok(()) Ok(())