Merge pull request 'Remove jsonrpc from peach-network' (#46) from split_network_logic into main
Reviewed-on: #46
This commit is contained in:
commit
4d6dbd511e
|
@ -2125,20 +2125,6 @@ dependencies = [
|
||||||
"void",
|
"void",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b7fd5681d13fda646462cfbd4e5f2051279a89a544d50eb98c365b507246839f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"bytes 0.4.12",
|
|
||||||
"cfg-if 0.1.10",
|
|
||||||
"gcc",
|
|
||||||
"libc",
|
|
||||||
"void",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
@ -2546,20 +2532,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peach-network"
|
name = "peach-network"
|
||||||
version = "0.2.12"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger 0.6.2",
|
|
||||||
"failure",
|
|
||||||
"get_if_addrs",
|
"get_if_addrs",
|
||||||
"jsonrpc-core 11.0.0",
|
"miniserde",
|
||||||
"jsonrpc-http-server 11.0.0",
|
|
||||||
"jsonrpc-test 11.0.0",
|
|
||||||
"log 0.4.14",
|
|
||||||
"probes 0.4.1",
|
"probes 0.4.1",
|
||||||
"regex",
|
"regex",
|
||||||
"serde 1.0.130",
|
"serde 1.0.130",
|
||||||
"serde_json",
|
|
||||||
"snafu 0.6.10",
|
|
||||||
"wpactrl",
|
"wpactrl",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4773,12 +4752,10 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wpactrl"
|
name = "wpactrl"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/sauyon/wpa-ctrl-rs.git?branch=master#e37eeb0a9b58cde12bc9825515caaaadcbf49fa6"
|
||||||
checksum = "f487ac0a84d67974aa9ca3a7a284cb4821869d677376768f5c303fa786635c13"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"failure",
|
"libc",
|
||||||
"log 0.4.14",
|
"log 0.4.14",
|
||||||
"nix 0.10.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -1,44 +1,32 @@
|
||||||
[package]
|
[package]
|
||||||
name = "peach-network"
|
name = "peach-network"
|
||||||
version = "0.2.12"
|
version = "0.3.0"
|
||||||
authors = ["Andrew Reid <gnomad@cryptolab.net>"]
|
authors = ["Andrew Reid <glyph@mycelial.technology>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Query and configure network interfaces using JSON-RPC over HTTP."
|
description = "Query and configure network interfaces."
|
||||||
homepage = "https://opencollective.com/peachcloud"
|
homepage = "https://opencollective.com/peachcloud"
|
||||||
repository = "https://github.com/peachcloud/peach-network"
|
repository = "ihttps://git.coopcloud.tech/PeachCloud/peach-workspace/src/branch/main/peach-network"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "AGPL-3.0-only"
|
license = "LGPL-3.0-only"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[package.metadata.deb]
|
|
||||||
depends = "$auto"
|
|
||||||
extended-description = """\
|
|
||||||
peach-network is a microservice to query and configure network interfaces \
|
|
||||||
using JSON-RPC over HTTP."""
|
|
||||||
maintainer-scripts="debian"
|
|
||||||
systemd-units = { unit-name = "peach-network" }
|
|
||||||
assets = [
|
|
||||||
["target/release/peach-network", "usr/bin/", "755"],
|
|
||||||
["README.md", "usr/share/doc/peach-network/README", "644"],
|
|
||||||
]
|
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "peachcloud/peach-network", branch = "master" }
|
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
env_logger = "0.6"
|
|
||||||
failure = "0.1"
|
|
||||||
get_if_addrs = "0.5.3"
|
get_if_addrs = "0.5.3"
|
||||||
jsonrpc-core = "11"
|
miniserde = { version = "0.1.15", optional = true }
|
||||||
jsonrpc-http-server = "11"
|
probes = "0.4.1"
|
||||||
log = "0.4"
|
serde = { version = "1.0.130", features = ["derive"], optional = true }
|
||||||
probes = "0.4"
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
|
||||||
serde_json = "1"
|
|
||||||
snafu = "0.6"
|
|
||||||
regex = "1"
|
regex = "1"
|
||||||
wpactrl = "0.3.1"
|
# replace this with crate import once latest changes have been published
|
||||||
|
wpactrl = { git = "https://github.com/sauyon/wpa-ctrl-rs.git", branch = "master" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[features]
|
||||||
jsonrpc-test = "11"
|
default = []
|
||||||
|
|
||||||
|
# Provide `Serialize` and `Deserialize` traits for library structs using `miniserde`
|
||||||
|
miniserde_support = ["miniserde"]
|
||||||
|
|
||||||
|
# Provide `Serialize` and `Deserialize` traits for library structs using `serde`
|
||||||
|
serde_support = ["serde"]
|
||||||
|
|
|
@ -1,178 +1,42 @@
|
||||||
# peach-network
|
# peach-network
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.com/peachcloud/peach-network.svg?branch=master)](https://travis-ci.com/peachcloud/peach-network) ![Generic badge](https://img.shields.io/badge/version-0.2.12-<COLOR>.svg)
|
![Generic badge](https://img.shields.io/badge/version-0.3.0-<COLOR>.svg)
|
||||||
|
|
||||||
Networking microservice module for PeachCloud. Query and configure device interfaces using [JSON-RPC](https://www.jsonrpc.org/specification) over http.
|
Network interface state query and modification library.
|
||||||
|
|
||||||
Interaction with wireless interfaces occurs primarily through the [wpactrl crate](https://docs.rs/wpactrl/0.3.1/wpactrl/) which provides "a pure-Rust lowlevel library for controlling wpasupplicant remotely". This approach is akin to using `wpa_cli` (a WPA command line client).
|
Interaction with wireless interfaces occurs primarily through the [wpactrl crate](https://docs.rs/wpactrl/0.3.1/wpactrl/) which provides "a pure-Rust lowlevel library for controlling wpasupplicant remotely". This approach is akin to using `wpa_cli` (a WPA command line client).
|
||||||
|
|
||||||
_Note: This module is a work-in-progress._
|
## API Documentation
|
||||||
|
|
||||||
### JSON-RPC API
|
API documentation can be built and served with `cargo doc --no-deps --open`. The full set of available data structures and functions is listed in the `peach_network::network` module. A custom error type (`NetworkError`) is also publically exposed for library users; it encapsulates all possible error variants.
|
||||||
|
|
||||||
Methods for **retrieving data**:
|
## Example Usage
|
||||||
|
|
||||||
| Method | Parameters | Description |
|
```rust
|
||||||
| --- | --- | --- |
|
use peach_network::{network, NetworkError};
|
||||||
| `available_networks` | `iface` | List SSID, flags (security), frequency and signal level for all networks in range of given interface |
|
|
||||||
| `id` | `iface`, `ssid` | Return ID of given SSID |
|
|
||||||
| `ip` | `iface` | Return IP of given network interface |
|
|
||||||
| `ping` | | Respond with `success` if microservice is running |
|
|
||||||
| `rssi` | `iface` | Return average signal strength (dBm) for given interface |
|
|
||||||
| `rssi_percent` | `iface` | Return average signal strength (%) for given interface |
|
|
||||||
| `saved_networks` | | List all networks saved in wpasupplicant config |
|
|
||||||
| `ssid` | `iface` | Return SSID of currently-connected network for given interface |
|
|
||||||
| `state` | `iface` | Return state of given interface |
|
|
||||||
| `status` | `iface` | Return status parameters for given interface |
|
|
||||||
| `traffic` | `iface` | Return network traffic for given interface |
|
|
||||||
|
|
||||||
Methods for **modifying state**:
|
fn main() -> Result<(), NetworkError> {
|
||||||
|
let ip = network::ip("wlan0")?;
|
||||||
|
let ssid = network::ssid("wlan0")?;
|
||||||
|
|
||||||
| Method | Parameters | Description |
|
let new_ap = Wifi { ssid: "Home".to_string(), pass: "SuperSecret".to_string() };
|
||||||
| --- | --- | --- |
|
network::add(new_ap)?;
|
||||||
| `activate_ap` | | Activate WiFi access point (start `wpa_supplicant@ap0.service`) |
|
network::save()?;
|
||||||
| `activate_client` | | Activate WiFi client connection (start `wpa_supplicant@wlan0.service`) |
|
|
||||||
| `add` | `ssid`, `pass` | Add WiFi credentials to `wpa_supplicant-wlan0.conf` |
|
|
||||||
| `check_iface` | | Activate WiFi access point if client mode is active without a connection |
|
|
||||||
| `connect` | `id`, `iface` | Disable other networks and attempt connection with AP represented by given id |
|
|
||||||
| `delete` | `id`, `iface` | Remove WiFi credentials for given network id and interface |
|
|
||||||
| `disable` | `id`, `iface` | Disable connection with AP represented by given id |
|
|
||||||
| `disconnect` | `iface` | Disconnect given interface |
|
|
||||||
| `modify` | `id`, `iface`, `password` | Set a new password for given network id and interface |
|
|
||||||
| `reassociate` | `iface` | Reassociate with current AP for given interface |
|
|
||||||
| `reconfigure` | | Force wpa_supplicant to re-read its configuration file |
|
|
||||||
| `reconnect` | `iface` | Disconnect and reconnect given interface |
|
|
||||||
| `save` | | Save configuration changes to `wpa_supplicant-wlan0.conf` |
|
|
||||||
|
|
||||||
### API Documentation
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
API documentation can be built and served with `cargo doc --no-deps --open`. This set of documentation is intended for developers who wish to work on the project or better understand the API of the `src/network.rs` module.
|
## Feature Flags
|
||||||
|
|
||||||
### Environment
|
Feature flags are used to offer `Serialize` and `Deserialize` implementations for all `struct` data types provided by this library. These traits are not provided by default. A choice of `miniserde` and `serde` is provided.
|
||||||
|
|
||||||
The JSON-RPC HTTP server address and port can be configured with the `PEACH_NETWORK_SERVER` environment variable:
|
Define the desired feature in the `Cargo.toml` manifest of your project:
|
||||||
|
|
||||||
`export PEACH_NETWORK_SERVER=127.0.0.1:5000`
|
```toml
|
||||||
|
peach-network = { version = "0.3.0", features = ["miniserde_support"] }
|
||||||
|
```
|
||||||
|
|
||||||
When not set, the value defaults to `127.0.0.1:5110`.
|
## License
|
||||||
|
|
||||||
Logging is made available with `env_logger`:
|
LGPL-3.0.
|
||||||
|
|
||||||
`export RUST_LOG=info`
|
|
||||||
|
|
||||||
Other logging levels include `debug`, `warn` and `error`.
|
|
||||||
|
|
||||||
### Setup
|
|
||||||
|
|
||||||
Clone this repo:
|
|
||||||
|
|
||||||
`git clone https://github.com/peachcloud/peach-network.git`
|
|
||||||
|
|
||||||
Move into the repo and compile:
|
|
||||||
|
|
||||||
`cd peach-network`
|
|
||||||
`cargo build --release`
|
|
||||||
|
|
||||||
Run the binary (sudo needed to satisfy permission requirements):
|
|
||||||
|
|
||||||
`sudo ./target/release/peach-network`
|
|
||||||
|
|
||||||
### Debian Packaging
|
|
||||||
|
|
||||||
A `systemd` service file and Debian maintainer scripts are included in the `debian` directory, allowing `peach-network` to be easily bundled as a Debian package (`.deb`). The `cargo-deb` [crate](https://crates.io/crates/cargo-deb) can be used to achieve this.
|
|
||||||
|
|
||||||
Install `cargo-deb`:
|
|
||||||
|
|
||||||
`cargo install cargo-deb`
|
|
||||||
|
|
||||||
Move into the repo:
|
|
||||||
|
|
||||||
`cd peach-network`
|
|
||||||
|
|
||||||
Build the package:
|
|
||||||
|
|
||||||
`cargo deb`
|
|
||||||
|
|
||||||
The output will be written to `target/debian/peach-network_0.2.4_arm64.deb` (or similar).
|
|
||||||
|
|
||||||
Build the package (aarch64):
|
|
||||||
|
|
||||||
`cargo deb --target aarch64-unknown-linux-gnu`
|
|
||||||
|
|
||||||
Install the package as follows:
|
|
||||||
|
|
||||||
`sudo dpkg -i target/debian/peach-network_0.2.4_arm64.deb`
|
|
||||||
|
|
||||||
The service will be automatically enabled and started.
|
|
||||||
|
|
||||||
Uninstall the service:
|
|
||||||
|
|
||||||
`sudo apt-get remove peach-network`
|
|
||||||
|
|
||||||
Remove configuration files (not removed with `apt-get remove`):
|
|
||||||
|
|
||||||
`sudo apt-get purge peach-network`
|
|
||||||
|
|
||||||
### Example Usage
|
|
||||||
|
|
||||||
**Retrieve IP address for wlan0**
|
|
||||||
|
|
||||||
With microservice running, open a second terminal window and use `curl` to call server methods:
|
|
||||||
|
|
||||||
`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "ip", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5110`
|
|
||||||
|
|
||||||
Server responds with:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","result":"192.168.1.21","id":1}`
|
|
||||||
|
|
||||||
**Retrieve SSID of connected access point for wlan1**
|
|
||||||
|
|
||||||
`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "ssid", "params" : {"iface": "wlan1" }, "id":1 }' 127.0.0.1:5110`
|
|
||||||
|
|
||||||
Server response when interface is connected:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","result":"Home","id":1}`
|
|
||||||
|
|
||||||
Server response when interface is not connected:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","error":{"code":-32003,"message":"Failed to retrieve SSID for wlan1. Interface may not be connected."},"id":1}`
|
|
||||||
|
|
||||||
**Retrieve list of SSIDs for all networks in range of wlan0**
|
|
||||||
|
|
||||||
`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "available_networks", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5110`
|
|
||||||
|
|
||||||
Server response when interface is connected:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","result":"[{\"frequency\":\"2412\",\"signal_level\":\"-72\",\"ssid\":\"Home\",\"flags\":\"[WPA2-PSK-CCMP][ESS]\"},{\"frequency\":\"2472\",\"signal_level\":\"-56\",\"ssid\":\"podetium\",\"flags\":\"[WPA2-PSK-CCMP+TKIP][ESS]\"}]","id":1}`
|
|
||||||
|
|
||||||
Server response when interface is not connected:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","error":{"code":-32006,"message":"No networks found in range of wlan0"},"id":1}`
|
|
||||||
|
|
||||||
**Retrieve network traffic statistics for wlan1**
|
|
||||||
|
|
||||||
`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "traffic", "params" : {"iface": "wlan1" }, "id":1 }' 127.0.0.1:5110`
|
|
||||||
|
|
||||||
Server response if interface exists:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","result":"{\"received\":26396361,\"transmitted\":22352530}","id":1}`
|
|
||||||
|
|
||||||
Server response when interface is not found:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","error":{"code":-32004,"message":"Failed to retrieve network traffic for wlan3. Interface may not be connected"},"id":1}`
|
|
||||||
|
|
||||||
**Retrieve status information for wlan0**
|
|
||||||
|
|
||||||
`curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "status", "params" : {"iface": "wlan0" }, "id":1 }' 127.0.0.1:5110`
|
|
||||||
|
|
||||||
Server response if interface exists:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","result":"{\"address\":\"b8:27:eb:9b:5d:5f\",\"bssid\":\"f4:8c:eb:cd:31:81\",\"freq\":\"2412\",\"group_cipher\":\"CCMP\",\"id\":\"0\",\"ip_address\":\"192.168.0.162\",\"key_mgmt\":\"WPA2-PSK\",\"mode\":\"station\",\"pairwise_cipher\":\"CCMP\",\"ssid\":\"Home\",\"wpa_state\":\"COMPLETED\"}","id":1}`
|
|
||||||
|
|
||||||
Server response when interface is not found:
|
|
||||||
|
|
||||||
`{"jsonrpc":"2.0","error":{"code":-32013,"message":"Failed to open control interface for wpasupplicant: No such file or directory (os error 2)"},"id":1}`
|
|
||||||
|
|
||||||
### Licensing
|
|
||||||
|
|
||||||
AGPL-3.0
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=Query and configure network interfaces using JSON-RPC over HTTP.
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
Group=netdev
|
|
||||||
Environment="RUST_LOG=error"
|
|
||||||
ExecStart=/usr/bin/peach-network
|
|
||||||
Restart=always
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
|
@ -1,351 +1,358 @@
|
||||||
use std::{error, io, str};
|
//! Custom error type for `peach-network`.
|
||||||
|
|
||||||
use jsonrpc_core::{types::error::Error, ErrorCode};
|
use std::io;
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
|
use io::Error as IoError;
|
||||||
use probes::ProbeError;
|
use probes::ProbeError;
|
||||||
use serde_json::error::Error as SerdeError;
|
use regex::Error as RegexError;
|
||||||
use snafu::Snafu;
|
use wpactrl::WpaError;
|
||||||
|
|
||||||
pub type BoxError = Box<dyn error::Error>;
|
/// Custom error type encapsulating all possible errors when querying
|
||||||
|
/// network interfaces and modifying their state.
|
||||||
#[derive(Debug, Snafu)]
|
#[derive(Debug)]
|
||||||
#[snafu(visibility(pub(crate)))]
|
|
||||||
pub enum NetworkError {
|
pub enum NetworkError {
|
||||||
#[snafu(display("{}", err_msg))]
|
/// Failed to add network.
|
||||||
ActivateAp { err_msg: String },
|
Add {
|
||||||
|
/// SSID.
|
||||||
#[snafu(display("{}", err_msg))]
|
ssid: String,
|
||||||
ActivateClient { err_msg: String },
|
},
|
||||||
|
/// Failed to retrieve network state.
|
||||||
#[snafu(display("Failed to add network for {}", ssid))]
|
NoState {
|
||||||
Add { ssid: String },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display("Failed to retrieve state for interface: {}", iface))]
|
/// Underlying error source.
|
||||||
NoState { iface: String, source: io::Error },
|
source: IoError,
|
||||||
|
},
|
||||||
#[snafu(display("Failed to disable network {} for interface: {}", id, iface))]
|
/// Failed to disable network.
|
||||||
Disable { id: String, iface: String },
|
Disable {
|
||||||
|
/// ID.
|
||||||
#[snafu(display("Failed to disconnect {}", iface))]
|
id: String,
|
||||||
Disconnect { iface: String },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display("Failed to generate wpa passphrase for {}: {}", ssid, source))]
|
},
|
||||||
GenWpaPassphrase { ssid: String, source: io::Error },
|
/// Failed to disconnect interface.
|
||||||
|
Disconnect {
|
||||||
#[snafu(display("Failed to generate wpa passphrase for {}: {}", ssid, err_msg))]
|
/// Interface.
|
||||||
GenWpaPassphraseWarning { ssid: String, err_msg: String },
|
iface: String,
|
||||||
|
},
|
||||||
#[snafu(display("No ID found for {} on interface: {}", ssid, iface))]
|
/// Failed to execute wpa_passphrase command.
|
||||||
Id { ssid: String, iface: String },
|
GenWpaPassphrase {
|
||||||
|
/// SSID.
|
||||||
#[snafu(display("Could not access IP address for interface: {}", iface))]
|
ssid: String,
|
||||||
NoIp { iface: String, source: io::Error },
|
/// Underlying error source.
|
||||||
|
source: IoError,
|
||||||
#[snafu(display("Could not find RSSI for interface: {}", iface))]
|
},
|
||||||
Rssi { iface: String },
|
/// Failed to successfully generate wpa passphrase.
|
||||||
|
GenWpaPassphraseWarning {
|
||||||
#[snafu(display("Could not find signal quality (%) for interface: {}", iface))]
|
/// SSID.
|
||||||
RssiPercent { iface: String },
|
ssid: String,
|
||||||
|
/// Error message describing context.
|
||||||
#[snafu(display("Could not find SSID for interface: {}", iface))]
|
err_msg: String,
|
||||||
Ssid { iface: String },
|
},
|
||||||
|
/// Failed to retrieve ID for the given SSID and interface.
|
||||||
#[snafu(display("No state found for interface: {}", iface))]
|
Id {
|
||||||
State { iface: String },
|
/// SSID.
|
||||||
|
ssid: String,
|
||||||
#[snafu(display("No status found for interface: {}", iface))]
|
/// Interface.
|
||||||
Status { iface: String },
|
iface: String,
|
||||||
|
},
|
||||||
#[snafu(display("Could not find network traffic for interface: {}", iface))]
|
/// Failed to retrieve IP address.
|
||||||
Traffic { iface: String },
|
NoIp {
|
||||||
|
/// Inteface.
|
||||||
#[snafu(display("No saved networks found for default interface"))]
|
iface: String,
|
||||||
|
/// Underlying error source.
|
||||||
|
source: IoError,
|
||||||
|
},
|
||||||
|
/// Failed to retrieve RSSI.
|
||||||
|
Rssi {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// Failed to retrieve signal quality (%).
|
||||||
|
RssiPercent {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// Failed to retrieve SSID.
|
||||||
|
Ssid {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// Failed to retrieve state.
|
||||||
|
State {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// Failed to retrieve status.
|
||||||
|
Status {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// Failed to retieve network traffic.
|
||||||
|
Traffic {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// No saved network found for the default interface.
|
||||||
SavedNetworks,
|
SavedNetworks,
|
||||||
|
/// No networks found in range.
|
||||||
#[snafu(display("No networks found in range of interface: {}", iface))]
|
AvailableNetworks {
|
||||||
AvailableNetworks { iface: String },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display("Missing expected parameters: {}", e))]
|
},
|
||||||
MissingParams { e: Error },
|
/// Failed to set new password.
|
||||||
|
Modify {
|
||||||
#[snafu(display("Failed to set new password for network {} on {}", id, iface))]
|
/// ID.
|
||||||
Modify { id: String, iface: String },
|
id: String,
|
||||||
|
/// Interface.
|
||||||
#[snafu(display("No IP found for interface: {}", iface))]
|
iface: String,
|
||||||
Ip { iface: String },
|
},
|
||||||
|
/// Failed to retrieve IP address.
|
||||||
#[snafu(display("Failed to parse integer from string for RSSI value: {}", source))]
|
Ip {
|
||||||
ParseString { source: std::num::ParseIntError },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display(
|
},
|
||||||
"Failed to retrieve network traffic measurement for {}: {}",
|
/// Failed to parse integer from string.
|
||||||
iface,
|
ParseInt(ParseIntError),
|
||||||
source
|
/// Failed to retrieve network traffic measurement.
|
||||||
))]
|
NoTraffic {
|
||||||
NoTraffic { iface: String, source: ProbeError },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display("Failed to reassociate with WiFi network for interface: {}", iface))]
|
/// Underlying error source.
|
||||||
Reassociate { iface: String },
|
source: ProbeError,
|
||||||
|
},
|
||||||
#[snafu(display("Failed to force reread of wpa_supplicant configuration file"))]
|
/// Failed to reassociate with WiFi network.
|
||||||
|
Reassociate {
|
||||||
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
|
},
|
||||||
|
/// Failed to force reread of wpa_supplicant configuration file.
|
||||||
Reconfigure,
|
Reconfigure,
|
||||||
|
/// Failed to reconnect with WiFi network.
|
||||||
#[snafu(display("Failed to reconnect with WiFi network for interface: {}", iface))]
|
Reconnect {
|
||||||
Reconnect { iface: String },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display("Regex command failed"))]
|
},
|
||||||
Regex { source: regex::Error },
|
/// Failed to execute Regex command.
|
||||||
|
Regex(RegexError),
|
||||||
#[snafu(display("Failed to delete network {} for interface: {}", id, iface))]
|
/// Failed to delete network.
|
||||||
Delete { id: String, iface: String },
|
Delete {
|
||||||
|
/// ID.
|
||||||
#[snafu(display("Failed to retrieve state of wlan0 service: {}", source))]
|
id: String,
|
||||||
WlanState { source: io::Error },
|
/// Interface.
|
||||||
|
iface: String,
|
||||||
#[snafu(display("Failed to retrieve connection state of wlan0 interface: {}", source))]
|
},
|
||||||
WlanOperstate { source: io::Error },
|
/// Failed to retrieve state of wlan0 service.
|
||||||
|
WlanState(IoError),
|
||||||
#[snafu(display("Failed to save configuration changes to file"))]
|
/// Failed to retrieve connection state of wlan0 interface.
|
||||||
|
WlanOperstate(IoError),
|
||||||
|
/// Failed to save wpa_supplicant configuration changes to file.
|
||||||
Save,
|
Save,
|
||||||
|
/// Failed to connect to network.
|
||||||
#[snafu(display("Failed to connect to network {} for interface: {}", id, iface))]
|
Connect {
|
||||||
Connect { id: String, iface: String },
|
/// ID.
|
||||||
|
id: String,
|
||||||
#[snafu(display("Failed to start ap0 service: {}", source))]
|
/// Interface.
|
||||||
StartAp0 { source: io::Error },
|
iface: String,
|
||||||
|
|
||||||
#[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,
|
|
||||||
},
|
|
||||||
|
|
||||||
#[snafu(display("Request to wpasupplicant via wpactrl failed"))]
|
|
||||||
WpaCtrlRequest {
|
|
||||||
#[snafu(source(from(failure::Error, std::convert::Into::into)))]
|
|
||||||
source: BoxError,
|
|
||||||
},
|
},
|
||||||
|
/// Failed to start ap0 service.
|
||||||
|
StartAp0(IoError),
|
||||||
|
/// Failed to start wlan0 service.
|
||||||
|
StartWlan0(IoError),
|
||||||
|
/// Failed to execute wpa-ctrl command.
|
||||||
|
WpaCtrl(WpaError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NetworkError> for Error {
|
impl std::error::Error for NetworkError {
|
||||||
fn from(err: NetworkError) -> Self {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match &err {
|
match *self {
|
||||||
NetworkError::ActivateAp { err_msg } => Error {
|
NetworkError::Add { .. } => None,
|
||||||
code: ErrorCode::ServerError(-32015),
|
NetworkError::NoState { ref source, .. } => Some(source),
|
||||||
message: err_msg.to_string(),
|
NetworkError::Disable { .. } => None,
|
||||||
data: None,
|
NetworkError::Disconnect { .. } => None,
|
||||||
},
|
NetworkError::GenWpaPassphrase { ref source, .. } => Some(source),
|
||||||
NetworkError::ActivateClient { err_msg } => Error {
|
NetworkError::GenWpaPassphraseWarning { .. } => None,
|
||||||
code: ErrorCode::ServerError(-32017),
|
NetworkError::Id { .. } => None,
|
||||||
message: err_msg.to_string(),
|
NetworkError::NoIp { ref source, .. } => Some(source),
|
||||||
data: None,
|
NetworkError::Rssi { .. } => None,
|
||||||
},
|
NetworkError::RssiPercent { .. } => None,
|
||||||
NetworkError::Add { ssid } => Error {
|
NetworkError::Ssid { .. } => None,
|
||||||
code: ErrorCode::ServerError(-32000),
|
NetworkError::State { .. } => None,
|
||||||
message: format!("Failed to add network for {}", ssid),
|
NetworkError::Status { .. } => None,
|
||||||
data: None,
|
NetworkError::Traffic { .. } => None,
|
||||||
},
|
NetworkError::SavedNetworks => None,
|
||||||
NetworkError::NoState { iface, source } => Error {
|
NetworkError::AvailableNetworks { .. } => None,
|
||||||
code: ErrorCode::ServerError(-32022),
|
NetworkError::Modify { .. } => None,
|
||||||
message: format!(
|
NetworkError::Ip { .. } => None,
|
||||||
"Failed to retrieve interface state for {}: {}",
|
NetworkError::ParseInt(ref source) => Some(source),
|
||||||
iface, source
|
NetworkError::NoTraffic { ref source, .. } => Some(source),
|
||||||
),
|
NetworkError::Reassociate { .. } => None,
|
||||||
data: None,
|
NetworkError::Reconfigure { .. } => None,
|
||||||
},
|
NetworkError::Reconnect { .. } => None,
|
||||||
NetworkError::Disable { id, iface } => Error {
|
NetworkError::Regex(ref source) => Some(source),
|
||||||
code: ErrorCode::ServerError(-32029),
|
NetworkError::Delete { .. } => None,
|
||||||
message: format!("Failed to disable network {} for {}", id, iface),
|
NetworkError::WlanState(ref source) => Some(source),
|
||||||
data: None,
|
NetworkError::WlanOperstate(ref source) => Some(source),
|
||||||
},
|
NetworkError::Save => None,
|
||||||
NetworkError::Disconnect { iface } => Error {
|
NetworkError::Connect { .. } => None,
|
||||||
code: ErrorCode::ServerError(-32032),
|
NetworkError::StartWlan0(ref source) => Some(source),
|
||||||
message: format!("Failed to disconnect {}", iface),
|
NetworkError::StartAp0(ref source) => Some(source),
|
||||||
data: None,
|
NetworkError::WpaCtrl(ref source) => Some(source),
|
||||||
},
|
|
||||||
NetworkError::GenWpaPassphrase { ssid, source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32025),
|
|
||||||
message: format!("Failed to generate wpa passphrase for {}: {}", ssid, source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::GenWpaPassphraseWarning { ssid, err_msg } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32036),
|
|
||||||
message: format!(
|
|
||||||
"Failed to generate wpa passphrase for {}: {}",
|
|
||||||
ssid, err_msg
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Id { iface, ssid } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32026),
|
|
||||||
message: format!("No ID found for {} on interface {}", ssid, iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::NoIp { iface, source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32001),
|
|
||||||
message: format!("Failed to retrieve IP address for {}: {}", iface, source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Rssi { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32002),
|
|
||||||
message: format!(
|
|
||||||
"Failed to retrieve RSSI for {}. Interface may not be connected",
|
|
||||||
iface
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::RssiPercent { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32034),
|
|
||||||
message: format!(
|
|
||||||
"Failed to retrieve signal quality (%) for {}. Interface may not be connected",
|
|
||||||
iface
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Ssid { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32003),
|
|
||||||
message: format!(
|
|
||||||
"Failed to retrieve SSID for {}. Interface may not be connected",
|
|
||||||
iface
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::State { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32023),
|
|
||||||
message: format!("No state found for {}. Interface may not exist", iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Status { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32024),
|
|
||||||
message: format!("No status found for {}. Interface may not exist", iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Traffic { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32004),
|
|
||||||
message: format!(
|
|
||||||
"No network traffic statistics found for {}. Interface may not exist",
|
|
||||||
iface
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::SavedNetworks => Error {
|
|
||||||
code: ErrorCode::ServerError(-32005),
|
|
||||||
message: "No saved networks found".to_string(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::AvailableNetworks { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32006),
|
|
||||||
message: format!("No networks found in range of {}", iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
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),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Ip { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32007),
|
|
||||||
message: format!("No IP address found for {}", iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::ParseString { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32035),
|
|
||||||
message: format!(
|
|
||||||
"Failed to parse integer from string for RSSI value: {}",
|
|
||||||
source
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::NoTraffic { iface, source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32015),
|
|
||||||
message: format!(
|
|
||||||
"Failed to retrieve network traffic statistics for {}: {}",
|
|
||||||
iface, source
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Reassociate { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32008),
|
|
||||||
message: format!("Failed to reassociate with WiFi network for {}", iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Reconfigure => Error {
|
|
||||||
code: ErrorCode::ServerError(-32030),
|
|
||||||
message: "Failed to force reread of wpa_supplicant configuration file".to_string(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Reconnect { iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32009),
|
|
||||||
message: format!("Failed to reconnect with WiFi network for {}", iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Regex { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32010),
|
|
||||||
message: format!("Regex command error: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Delete { id, iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32028),
|
|
||||||
message: format!("Failed to delete network {} for {}", id, iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::WlanState { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32011),
|
|
||||||
message: format!("Failed to retrieve state of wlan0 service: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::WlanOperstate { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32021),
|
|
||||||
message: format!(
|
|
||||||
"Failed to retrieve connection state of wlan0 interface: {}",
|
|
||||||
source
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Save => Error {
|
|
||||||
code: ErrorCode::ServerError(-32031),
|
|
||||||
message: "Failed to save configuration changes to file".to_string(),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::Connect { id, iface } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32027),
|
|
||||||
message: format!("Failed to connect to network {} for {}", id, iface),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::StartAp0 { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32016),
|
|
||||||
message: format!("Failed to start ap0 service: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::StartWlan0 { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32018),
|
|
||||||
message: format!("Failed to start wlan0 service: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::SerdeSerialize { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32012),
|
|
||||||
message: format!("JSON serialization failed: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::WpaCtrlOpen { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32013),
|
|
||||||
message: format!(
|
|
||||||
"Failed to open control interface for wpasupplicant: {}",
|
|
||||||
source
|
|
||||||
),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
NetworkError::WpaCtrlRequest { source } => Error {
|
|
||||||
code: ErrorCode::ServerError(-32014),
|
|
||||||
message: format!("WPA supplicant request failed: {}", source),
|
|
||||||
data: None,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 traffic for interface: {}", iface)
|
||||||
|
}
|
||||||
|
NetworkError::SavedNetworks => {
|
||||||
|
write!(f, "No saved networks found for default interface")
|
||||||
|
}
|
||||||
|
NetworkError::AvailableNetworks { ref iface } => {
|
||||||
|
write!(f, "No networks found in range of interface: {}", iface)
|
||||||
|
}
|
||||||
|
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::ParseInt(_) => {
|
||||||
|
write!(f, "Failed to parse integer from string for RSSI value")
|
||||||
|
}
|
||||||
|
NetworkError::NoTraffic { ref iface, .. } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Failed to retrieve network traffic measurement for {}",
|
||||||
|
iface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
NetworkError::Reassociate { ref iface } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Failed to reassociate with WiFi network for interface: {}",
|
||||||
|
iface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
NetworkError::Reconfigure => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"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!(f, "Regex command failed"),
|
||||||
|
NetworkError::Delete { ref id, ref iface } => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Failed to delete network {} for interface: {}",
|
||||||
|
id, iface
|
||||||
|
)
|
||||||
|
}
|
||||||
|
NetworkError::WlanState(_) => write!(f, "Failed to retrieve state of wlan0 service"),
|
||||||
|
NetworkError::WlanOperstate(_) => {
|
||||||
|
write!(f, "Failed to retrieve connection state of wlan0 interface")
|
||||||
|
}
|
||||||
|
NetworkError::Save => write!(f, "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!(f, "Failed to start ap0 service"),
|
||||||
|
NetworkError::StartAp0(_) => write!(f, "Failed to start wlan0 service"),
|
||||||
|
NetworkError::WpaCtrl(_) => write!(f, "WpaCtrl command failed"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WpaError> for NetworkError {
|
||||||
|
fn from(err: WpaError) -> Self {
|
||||||
|
NetworkError::WpaCtrl(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for NetworkError {
|
||||||
|
fn from(err: ParseIntError) -> Self {
|
||||||
|
NetworkError::ParseInt(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RegexError> for NetworkError {
|
||||||
|
fn from(err: RegexError) -> Self {
|
||||||
|
NetworkError::Regex(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +0,0 @@
|
||||||
use std::process;
|
|
||||||
|
|
||||||
use log::error;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// initalize the logger
|
|
||||||
env_logger::init();
|
|
||||||
|
|
||||||
// handle errors returned from `run`
|
|
||||||
if let Err(e) = peach_network::run() {
|
|
||||||
error!("Application error: {}", e);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Retrieve network data and modify interface state.
|
//! Retrieve network data and modify interface state.
|
||||||
//!
|
//!
|
||||||
//! This module contains the core logic of the `peach-network` microservice and
|
//! This module contains the core logic of the `peach-network` and
|
||||||
//! provides convenience wrappers for a range of `wpasupplicant` commands,
|
//! provides convenience wrappers for a range of `wpasupplicant` commands,
|
||||||
//! many of which are ordinarily executed using `wpa_cli` (a WPA command line
|
//! many of which are ordinarily executed using `wpa_cli` (a WPA command line
|
||||||
//! client).
|
//! client).
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
//! 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-wlan0.conf`.
|
||||||
//!
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::OpenOptions,
|
fs::OpenOptions,
|
||||||
io::prelude::*,
|
io::prelude::*,
|
||||||
|
@ -21,72 +21,67 @@ use std::{
|
||||||
str,
|
str,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::{
|
|
||||||
GenWpaPassphrase, NetworkError, NoIp, NoState, NoTraffic, ParseString, SerdeSerialize,
|
|
||||||
StartAp0, StartWlan0, WlanState, WpaCtrlOpen, WpaCtrlRequest,
|
|
||||||
};
|
|
||||||
use probes::network;
|
use probes::network;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use snafu::ResultExt;
|
|
||||||
|
|
||||||
|
#[cfg(feature = "miniserde_support")]
|
||||||
|
use miniserde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "serde_support")]
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::error::NetworkError;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
/// Network interface name.
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct Iface {
|
|
||||||
pub iface: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network interface name and network identifier.
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct IfaceId {
|
|
||||||
pub iface: String,
|
|
||||||
pub id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network interface name, network identifier and password.
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct IfaceIdPass {
|
|
||||||
pub iface: String,
|
|
||||||
pub id: String,
|
|
||||||
pub pass: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network interface name and network SSID.
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
pub struct IfaceSsid {
|
|
||||||
pub iface: String,
|
|
||||||
pub ssid: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Network SSID.
|
/// Network SSID.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||||
pub struct Network {
|
pub struct Network {
|
||||||
|
/// Service Set Identifier (SSID).
|
||||||
pub ssid: String,
|
pub ssid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access point data retrieved via scan.
|
/// Access point data retrieved via scan.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||||
pub struct Scan {
|
pub struct Scan {
|
||||||
|
/// Frequency.
|
||||||
pub frequency: String,
|
pub frequency: String,
|
||||||
|
/// Protocol.
|
||||||
pub protocol: String,
|
pub protocol: String,
|
||||||
|
/// Signal strength.
|
||||||
pub signal_level: String,
|
pub signal_level: String,
|
||||||
|
/// SSID.
|
||||||
pub ssid: String,
|
pub ssid: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Status data for a network interface.
|
/// Status data for a network interface.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||||
pub struct Status {
|
pub struct Status {
|
||||||
|
/// MAC address.
|
||||||
pub address: Option<String>,
|
pub address: Option<String>,
|
||||||
|
/// Basic Service Set Identifier (BSSID).
|
||||||
pub bssid: Option<String>,
|
pub bssid: Option<String>,
|
||||||
|
/// Frequency.
|
||||||
pub freq: Option<String>,
|
pub freq: Option<String>,
|
||||||
|
/// Group cipher.
|
||||||
pub group_cipher: Option<String>,
|
pub group_cipher: Option<String>,
|
||||||
|
/// Local ID.
|
||||||
pub id: Option<String>,
|
pub id: Option<String>,
|
||||||
|
/// IP address.
|
||||||
pub ip_address: Option<String>,
|
pub ip_address: Option<String>,
|
||||||
|
/// Key management.
|
||||||
pub key_mgmt: Option<String>,
|
pub key_mgmt: Option<String>,
|
||||||
|
/// Mode.
|
||||||
pub mode: Option<String>,
|
pub mode: Option<String>,
|
||||||
|
/// Pairwise cipher.
|
||||||
pub pairwise_cipher: Option<String>,
|
pub pairwise_cipher: Option<String>,
|
||||||
|
/// SSID.
|
||||||
pub ssid: Option<String>,
|
pub ssid: Option<String>,
|
||||||
|
/// WPA state.
|
||||||
pub wpa_state: Option<String>,
|
pub wpa_state: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,16 +104,24 @@ impl Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Received and transmitted network traffic (bytes).
|
/// Received and transmitted network traffic (bytes).
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||||
pub struct Traffic {
|
pub struct Traffic {
|
||||||
|
/// Total bytes received.
|
||||||
pub received: u64,
|
pub received: u64,
|
||||||
|
/// Total bytes transmitted.
|
||||||
pub transmitted: u64,
|
pub transmitted: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SSID and password for a wireless access point.
|
/// SSID and password for a wireless access point.
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "miniserde_support", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
|
||||||
pub struct WiFi {
|
pub struct WiFi {
|
||||||
|
/// SSID.
|
||||||
pub ssid: String,
|
pub ssid: String,
|
||||||
|
/// Password.
|
||||||
pub pass: String,
|
pub pass: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,22 +135,15 @@ pub struct WiFi {
|
||||||
/// * `iface` - A string slice holding the name of a wireless network interface
|
/// * `iface` - A string slice holding the name of a wireless network interface
|
||||||
///
|
///
|
||||||
/// If the scan results include one or more access points for the given network
|
/// If the scan results include one or more access points for the given network
|
||||||
/// interface, an `Ok` `Result` type is returned containing `Some(String)` -
|
/// interface, an `Ok` `Result` type is returned containing `Some(Vec<Scan>)`.
|
||||||
/// where `String` is a serialized vector of `Scan` structs containing
|
/// The vector of `Scan` structs contains data for the in-range access points.
|
||||||
/// data for the in-range access points. If no access points are found,
|
/// If no access points are found, a `None` type is returned in the `Result`.
|
||||||
/// a `None` type is returned in the `Result`. In the event of an error, a
|
/// In the event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// `NetworkError` is returned in the `Result`. The `NetworkError` is then
|
pub fn available_networks(iface: &str) -> Result<Option<Vec<Scan>>, NetworkError> {
|
||||||
/// enumerated to a specific error type and an appropriate JSON RPC response is
|
|
||||||
/// sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn available_networks(iface: &str) -> Result<Option<String>, NetworkError> {
|
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
wpa.request("SCAN")?;
|
||||||
.open()
|
let networks = wpa.request("SCAN_RESULTS")?;
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
wpa.request("SCAN").context(WpaCtrlRequest)?;
|
|
||||||
let networks = wpa.request("SCAN_RESULTS").context(WpaCtrlRequest)?;
|
|
||||||
let mut scan = Vec::new();
|
let mut scan = Vec::new();
|
||||||
for network in networks.lines() {
|
for network in networks.lines() {
|
||||||
let v: Vec<&str> = network.split('\t').collect();
|
let v: Vec<&str> = network.split('\t').collect();
|
||||||
|
@ -178,8 +174,7 @@ pub fn available_networks(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
if scan.is_empty() {
|
if scan.is_empty() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
let results = serde_json::to_string(&scan).context(SerdeSerialize)?;
|
Ok(Some(scan))
|
||||||
Ok(Some(results))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,17 +190,11 @@ pub fn available_networks(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// found in the list of saved networks, an `Ok` `Result` type is returned
|
/// found in the list of saved networks, an `Ok` `Result` type is returned
|
||||||
/// containing `Some(String)` - where `String` is the network identifier.
|
/// containing `Some(String)` - where `String` is the network identifier.
|
||||||
/// If no match is found, a `None` type is returned in the `Result`. In the
|
/// If no match is found, a `None` type is returned in the `Result`. In the
|
||||||
/// event of an error, a `NetworkError` is returned in the `Result`. The
|
/// event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// `NetworkError` is then enumerated to a specific error type and an
|
|
||||||
/// appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn id(iface: &str, ssid: &str) -> Result<Option<String>, NetworkError> {
|
pub fn id(iface: &str, ssid: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
let networks = wpa.request("LIST_NETWORKS")?;
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?;
|
|
||||||
let mut id = Vec::new();
|
let mut id = Vec::new();
|
||||||
for network in networks.lines() {
|
for network in networks.lines() {
|
||||||
let v: Vec<&str> = network.split('\t').collect();
|
let v: Vec<&str> = network.split('\t').collect();
|
||||||
|
@ -233,13 +222,13 @@ pub fn id(iface: &str, ssid: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// an `Ok` `Result` type is returned containing `Some(String)` - where `String`
|
/// an `Ok` `Result` type is returned containing `Some(String)` - where `String`
|
||||||
/// is the IP address of the interface. If no match is found, a `None` type is
|
/// is the IP address of the interface. If no match is found, a `None` type is
|
||||||
/// returned in the `Result`. In the event of an error, a `NetworkError` is
|
/// returned in the `Result`. In the event of an error, a `NetworkError` is
|
||||||
/// returned in the `Result`. The `NetworkError` is then enumerated to a
|
/// returned in the `Result`.
|
||||||
/// specific error type and an appropriate JSON RPC response is sent to the
|
|
||||||
/// caller.
|
|
||||||
///
|
|
||||||
pub fn ip(iface: &str) -> Result<Option<String>, NetworkError> {
|
pub fn ip(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let net_if: String = iface.to_string();
|
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(|source| NetworkError::NoIp {
|
||||||
|
iface: net_if,
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
let ip = ifaces
|
let ip = ifaces
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&i| i.name == iface)
|
.find(|&i| i.name == iface)
|
||||||
|
@ -260,16 +249,11 @@ pub fn ip(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// is the RSSI (Received Signal Strength Indicator) of the connection measured
|
/// is the RSSI (Received Signal Strength Indicator) of the connection measured
|
||||||
/// in dBm. If signal strength is not found, a `None` type is returned in the
|
/// in dBm. If signal strength is not found, a `None` type is returned in the
|
||||||
/// `Result`. In the event of an error, a `NetworkError` is returned in the
|
/// `Result`. In the event of an error, a `NetworkError` is returned in the
|
||||||
/// `Result`. The `NetworkError` is then enumerated to a specific error type and
|
/// `Result`.
|
||||||
/// an appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn rssi(iface: &str) -> Result<Option<String>, NetworkError> {
|
pub fn rssi(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
let status = wpa.request("SIGNAL_POLL")?;
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?;
|
|
||||||
let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?;
|
let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?;
|
||||||
|
|
||||||
if rssi.is_none() {
|
if rssi.is_none() {
|
||||||
|
@ -292,22 +276,17 @@ pub fn rssi(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// is the RSSI (Received Signal Strength Indicator) of the connection measured
|
/// is the RSSI (Received Signal Strength Indicator) of the connection measured
|
||||||
/// as a percentage. If signal strength is not found, a `None` type is returned
|
/// as a percentage. If signal strength is not found, a `None` type is returned
|
||||||
/// in the `Result`. In the event of an error, a `NetworkError` is returned in
|
/// in the `Result`. In the event of an error, a `NetworkError` is returned in
|
||||||
/// the `Result`. The `NetworkError` is then enumerated to a specific error type
|
/// the `Result`.
|
||||||
/// and an appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn rssi_percent(iface: &str) -> Result<Option<String>, NetworkError> {
|
pub fn rssi_percent(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
let status = wpa.request("SIGNAL_POLL")?;
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let status = wpa.request("SIGNAL_POLL").context(WpaCtrlRequest)?;
|
|
||||||
let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?;
|
let rssi = utils::regex_finder(r"RSSI=(.*)\n", &status)?;
|
||||||
|
|
||||||
match rssi {
|
match rssi {
|
||||||
Some(rssi) => {
|
Some(rssi) => {
|
||||||
// parse the string to a signed integer (for math)
|
// parse the string to a signed integer (for math)
|
||||||
let rssi_parsed = rssi.parse::<i32>().context(ParseString)?;
|
let rssi_parsed = rssi.parse::<i32>()?;
|
||||||
// perform rssi (dBm) to quality (%) conversion
|
// perform rssi (dBm) to quality (%) conversion
|
||||||
let quality_percent = 2 * (rssi_parsed + 100);
|
let quality_percent = 2 * (rssi_parsed + 100);
|
||||||
// convert signal quality integer to string
|
// convert signal quality integer to string
|
||||||
|
@ -327,16 +306,13 @@ pub fn rssi_percent(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
///
|
///
|
||||||
/// If the wpasupplicant configuration file contains credentials for one or
|
/// If the wpasupplicant configuration file contains credentials for one or
|
||||||
/// more access points, an `Ok` `Result` type is returned containing
|
/// more access points, an `Ok` `Result` type is returned containing
|
||||||
/// `Some(String)` - where `String` is a serialized vector of `Network` structs
|
/// `Some(Vec<Network>)`. The vector of `Network` structs contains the SSIDs
|
||||||
/// containing the SSIDs of all saved networks. If no network credentials are
|
/// of all saved networks. If no network credentials are found, a `None` type
|
||||||
/// found, a `None` type is returned in the `Result`. In the event of an error,
|
/// is returned in the `Result`. In the event of an error, a `NetworkError` is
|
||||||
/// a `NetworkError` is returned in the `Result`. The `NetworkError` is then
|
/// returned in the `Result`.
|
||||||
/// enumerated to a specific error type and an appropriate JSON RPC response is
|
pub fn saved_networks() -> Result<Option<Vec<Network>>, NetworkError> {
|
||||||
/// sent to the caller.
|
let mut wpa = wpactrl::WpaCtrl::builder().open()?;
|
||||||
///
|
let networks = wpa.request("LIST_NETWORKS")?;
|
||||||
pub fn saved_networks() -> Result<Option<String>, NetworkError> {
|
|
||||||
let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?;
|
|
||||||
let networks = wpa.request("LIST_NETWORKS").context(WpaCtrlRequest)?;
|
|
||||||
let mut ssids = Vec::new();
|
let mut ssids = Vec::new();
|
||||||
for network in networks.lines() {
|
for network in networks.lines() {
|
||||||
let v: Vec<&str> = network.split('\t').collect();
|
let v: Vec<&str> = network.split('\t').collect();
|
||||||
|
@ -351,8 +327,7 @@ pub fn saved_networks() -> Result<Option<String>, NetworkError> {
|
||||||
if ssids.is_empty() {
|
if ssids.is_empty() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
let results = serde_json::to_string(&ssids).context(SerdeSerialize)?;
|
Ok(Some(ssids))
|
||||||
Ok(Some(results))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,17 +341,11 @@ pub fn saved_networks() -> Result<Option<String>, NetworkError> {
|
||||||
/// an `Ok` `Result` type is returned containing `Some(String)` - where `String`
|
/// an `Ok` `Result` type is returned containing `Some(String)` - where `String`
|
||||||
/// is the SSID of the associated network. If SSID is not found, a `None` type
|
/// is the SSID of the associated network. If SSID is not found, a `None` type
|
||||||
/// is returned in the `Result`. In the event of an error, a `NetworkError` is
|
/// is returned in the `Result`. In the event of an error, a `NetworkError` is
|
||||||
/// returned in the `Result`. The `NetworkError` is then enumerated to a
|
/// returned in the `Result`.
|
||||||
/// specific error type and an appropriate JSON RPC response is sent to the
|
|
||||||
/// caller.
|
|
||||||
///
|
|
||||||
pub fn ssid(iface: &str) -> Result<Option<String>, NetworkError> {
|
pub fn ssid(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
let status = wpa.request("STATUS")?;
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let status = wpa.request("STATUS").context(WpaCtrlRequest)?;
|
|
||||||
|
|
||||||
// pass the regex pattern and status output to the regex finder
|
// pass the regex pattern and status output to the regex finder
|
||||||
let ssid = utils::regex_finder(r"\nssid=(.*)\n", &status)?;
|
let ssid = utils::regex_finder(r"\nssid=(.*)\n", &status)?;
|
||||||
|
@ -394,9 +363,7 @@ pub fn ssid(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// returned containing `Some(String)` - where `String` is the state of the
|
/// returned containing `Some(String)` - where `String` is the state of the
|
||||||
/// network interface. If state is not found, a `None` type is returned in the
|
/// network interface. If state is not found, a `None` type is returned in the
|
||||||
/// `Result`. In the event of an error, a `NetworkError` is returned in the
|
/// `Result`. In the event of an error, a `NetworkError` is returned in the
|
||||||
/// `Result`. The `NetworkError` is then enumerated to a specific error type and
|
/// `Result`.
|
||||||
/// an appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn state(iface: &str) -> Result<Option<String>, NetworkError> {
|
pub fn state(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
// construct the interface operstate path
|
// construct the interface operstate path
|
||||||
let iface_path: String = format!("/sys/class/net/{}/operstate", iface);
|
let iface_path: String = format!("/sys/class/net/{}/operstate", iface);
|
||||||
|
@ -404,7 +371,10 @@ pub fn state(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let output = Command::new("cat")
|
let output = Command::new("cat")
|
||||||
.arg(iface_path)
|
.arg(iface_path)
|
||||||
.output()
|
.output()
|
||||||
.context(NoState { iface })?;
|
.map_err(|source| NetworkError::NoState {
|
||||||
|
iface: iface.to_string(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
if !output.stdout.is_empty() {
|
if !output.stdout.is_empty() {
|
||||||
// unwrap the command result and convert to String
|
// unwrap the command result and convert to String
|
||||||
let mut state = String::from_utf8(output.stdout).unwrap();
|
let mut state = String::from_utf8(output.stdout).unwrap();
|
||||||
|
@ -427,17 +397,11 @@ pub fn state(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// returned containing `Some(Status)` - where `Status` is a `struct`
|
/// returned containing `Some(Status)` - where `Status` is a `struct`
|
||||||
/// containing the aggregated interface data in named fields. If status is not
|
/// containing the aggregated interface data in named fields. If status is not
|
||||||
/// found, a `None` type is returned in the `Result`. In the event of an error,
|
/// found, a `None` type is returned in the `Result`. In the event of an error,
|
||||||
/// a `NetworkError` is returned in the `Result`. The `NetworkError` is then
|
/// a `NetworkError` is returned in the `Result`.
|
||||||
/// enumerated to a specific error type and an appropriate JSON RPC response is
|
|
||||||
/// sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn status(iface: &str) -> Result<Option<Status>, NetworkError> {
|
pub fn status(iface: &str) -> Result<Option<Status>, NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
let wpa_status = wpa.request("STATUS")?;
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let wpa_status = wpa.request("STATUS").context(WpaCtrlRequest)?;
|
|
||||||
|
|
||||||
// pass the regex pattern and status output to the regex finder
|
// pass the regex pattern and status output to the regex finder
|
||||||
let state = utils::regex_finder(r"wpa_state=(.*)\n", &wpa_status)?;
|
let state = utils::regex_finder(r"wpa_state=(.*)\n", &wpa_status)?;
|
||||||
|
@ -486,16 +450,16 @@ pub fn status(iface: &str) -> Result<Option<Status>, NetworkError> {
|
||||||
/// * `iface` - A string slice holding the name of a wireless network interface
|
/// * `iface` - A string slice holding the name of a wireless network interface
|
||||||
///
|
///
|
||||||
/// If the network traffic statistics are found for the given interface, an `Ok`
|
/// If the network traffic statistics are found for the given interface, an `Ok`
|
||||||
/// `Result` type is returned containing `Some(String)` - where `String` is a
|
/// `Result` type is returned containing `Some(Traffic)`. The `Traffic` `struct`
|
||||||
/// serialized `Traffic` `struct` with fields for received and transmitted
|
/// includes fields for received and transmitted network data statistics. If
|
||||||
/// network data statistics. If network traffic statistics are not found for the
|
/// network traffic statistics are not found for the given interface, a `None`
|
||||||
/// given interface, a `None` type is returned in the `Result`. In the event of
|
/// type is returned in the `Result`. In the event of an error, a `NetworkError`
|
||||||
/// an error, a `NetworkError` is returned in the `Result`. The `NetworkError`
|
/// is returned in the `Result`.
|
||||||
/// is then enumerated to a specific error type and an appropriate JSON RPC
|
pub fn traffic(iface: &str) -> Result<Option<Traffic>, NetworkError> {
|
||||||
/// response is sent to the caller.
|
let network = network::read().map_err(|source| NetworkError::NoTraffic {
|
||||||
///
|
iface: iface.to_string(),
|
||||||
pub fn traffic(iface: &str) -> Result<Option<String>, NetworkError> {
|
source,
|
||||||
let network = network::read().context(NoTraffic { iface })?;
|
})?;
|
||||||
// iterate through interfaces returned in network data
|
// iterate through interfaces returned in network data
|
||||||
for (interface, traffic) in network.interfaces {
|
for (interface, traffic) in network.interfaces {
|
||||||
if interface == iface {
|
if interface == iface {
|
||||||
|
@ -505,9 +469,7 @@ pub fn traffic(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
received,
|
received,
|
||||||
transmitted,
|
transmitted,
|
||||||
};
|
};
|
||||||
// TODO: add test for SerdeSerialize error
|
return Ok(Some(traffic));
|
||||||
let t = serde_json::to_string(&traffic).context(SerdeSerialize)?;
|
|
||||||
return Ok(Some(t));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,9 +483,6 @@ pub fn traffic(iface: &str) -> Result<Option<String>, NetworkError> {
|
||||||
/// A `systemctl `command is invoked which starts the `ap0` interface service.
|
/// A `systemctl `command is invoked which starts the `ap0` interface service.
|
||||||
/// If the command executes successfully, an `Ok` `Result` type is returned.
|
/// If the command executes successfully, an `Ok` `Result` type is returned.
|
||||||
/// In the event of an error, a `NetworkError` is returned in the `Result`.
|
/// In the event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// The `NetworkError` is then enumerated to a specific error type and an
|
|
||||||
/// appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn activate_ap() -> Result<(), NetworkError> {
|
pub fn activate_ap() -> Result<(), NetworkError> {
|
||||||
// start the ap0 interface service
|
// start the ap0 interface service
|
||||||
Command::new("sudo")
|
Command::new("sudo")
|
||||||
|
@ -531,7 +490,7 @@ pub fn activate_ap() -> Result<(), NetworkError> {
|
||||||
.arg("start")
|
.arg("start")
|
||||||
.arg("wpa_supplicant@ap0.service")
|
.arg("wpa_supplicant@ap0.service")
|
||||||
.output()
|
.output()
|
||||||
.context(StartAp0)?;
|
.map_err(NetworkError::StartAp0)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -541,9 +500,6 @@ pub fn activate_ap() -> Result<(), NetworkError> {
|
||||||
/// A `systemctl` command is invoked which starts the `wlan0` interface service.
|
/// A `systemctl` command is invoked which starts the `wlan0` interface service.
|
||||||
/// If the command executes successfully, an `Ok` `Result` type is returned.
|
/// If the command executes successfully, an `Ok` `Result` type is returned.
|
||||||
/// In the event of an error, a `NetworkError` is returned in the `Result`.
|
/// In the event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// The `NetworkError` is then enumerated to a specific error type and an
|
|
||||||
/// appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn activate_client() -> Result<(), NetworkError> {
|
pub fn activate_client() -> Result<(), NetworkError> {
|
||||||
// start the wlan0 interface service
|
// start the wlan0 interface service
|
||||||
Command::new("sudo")
|
Command::new("sudo")
|
||||||
|
@ -551,7 +507,7 @@ pub fn activate_client() -> Result<(), NetworkError> {
|
||||||
.arg("start")
|
.arg("start")
|
||||||
.arg("wpa_supplicant@wlan0.service")
|
.arg("wpa_supplicant@wlan0.service")
|
||||||
.output()
|
.output()
|
||||||
.context(StartWlan0)?;
|
.map_err(NetworkError::StartWlan0)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -565,10 +521,7 @@ pub fn activate_client() -> Result<(), NetworkError> {
|
||||||
/// 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-wlan0.conf`, an `Ok`
|
||||||
/// `Result` type is returned. In the event of an error, a `NetworkError` is
|
/// `Result` type is returned. In the event of an error, a `NetworkError` is
|
||||||
/// returned in the `Result`. The `NetworkError` is then enumerated to a
|
/// returned in the `Result`.
|
||||||
/// specific error type and an appropriate JSON RPC response is sent to the
|
|
||||||
/// caller.
|
|
||||||
///
|
|
||||||
pub fn add(wifi: &WiFi) -> Result<(), NetworkError> {
|
pub fn add(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")
|
||||||
|
@ -576,7 +529,10 @@ pub fn add(wifi: &WiFi) -> Result<(), NetworkError> {
|
||||||
.arg(&wifi.pass)
|
.arg(&wifi.pass)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.output()
|
.output()
|
||||||
.context(GenWpaPassphrase { ssid: &wifi.ssid })?;
|
.map_err(|source| NetworkError::GenWpaPassphrase {
|
||||||
|
ssid: wifi.ssid.to_string(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
// prepend newline to wpa_details to safeguard against malformed supplicant
|
// prepend newline to wpa_details to safeguard against malformed supplicant
|
||||||
let mut wpa_details = "\n".as_bytes().to_vec();
|
let mut wpa_details = "\n".as_bytes().to_vec();
|
||||||
|
@ -614,14 +570,13 @@ pub fn add(wifi: &WiFi) -> Result<(), NetworkError> {
|
||||||
/// 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() -> Result<(), NetworkError> {
|
||||||
// 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 wlan0_status = Command::new("/usr/bin/systemctl")
|
||||||
.arg("is-active")
|
.arg("is-active")
|
||||||
.arg("wpa_supplicant@wlan0.service")
|
.arg("wpa_supplicant@wlan0.service")
|
||||||
.status()
|
.status()
|
||||||
.context(WlanState)?;
|
.map_err(NetworkError::WlanState)?;
|
||||||
|
|
||||||
// returns the current state of the wlan0 interface
|
// returns the current state of the wlan0 interface
|
||||||
let iface_state = state("wlan0")?;
|
let iface_state = state("wlan0")?;
|
||||||
|
@ -651,18 +606,12 @@ pub fn check_iface() -> Result<(), NetworkError> {
|
||||||
/// If the network connection is successfully activated for the access point
|
/// If the network connection is successfully activated for the access point
|
||||||
/// represented by the given network identifier on the given wireless interface,
|
/// represented by the given network identifier on the given wireless interface,
|
||||||
/// an `Ok` `Result`type is returned. In the event of an error, a `NetworkError`
|
/// an `Ok` `Result`type is returned. In the event of an error, a `NetworkError`
|
||||||
/// is returned in the `Result`. The `NetworkError` is then enumerated to a
|
/// is returned in the `Result`.
|
||||||
/// specific error type and an appropriate JSON RPC response is sent to the
|
|
||||||
/// caller.
|
|
||||||
///
|
|
||||||
pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> {
|
pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let select = format!("SELECT {}", id);
|
let select = format!("SELECT {}", id);
|
||||||
wpa.request(&select).context(WpaCtrlRequest)?;
|
wpa.request(&select)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,18 +625,12 @@ pub fn connect(id: &str, iface: &str) -> Result<(), NetworkError> {
|
||||||
/// If the network configuration parameters are successfully deleted for
|
/// If the network configuration parameters are successfully deleted for
|
||||||
/// the access point represented by the given network identifier, an `Ok`
|
/// the access point represented by the given network identifier, an `Ok`
|
||||||
/// `Result`type is returned. In the event of an error, a `NetworkError` is
|
/// `Result`type is returned. In the event of an error, a `NetworkError` is
|
||||||
/// returned in the `Result`. The `NetworkError` is then enumerated to a
|
/// returned in the `Result`.
|
||||||
/// specific error type and an appropriate JSON RPC response is sent to the
|
|
||||||
/// caller.
|
|
||||||
///
|
|
||||||
pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> {
|
pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let remove = format!("REMOVE_NETWORK {}", id);
|
let remove = format!("REMOVE_NETWORK {}", id);
|
||||||
wpa.request(&remove).context(WpaCtrlRequest)?;
|
wpa.request(&remove)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,17 +644,12 @@ pub fn delete(id: &str, iface: &str) -> Result<(), NetworkError> {
|
||||||
/// If the network connection is successfully disabled for the access point
|
/// If the network connection is successfully disabled for the access point
|
||||||
/// represented by the given network identifier, an `Ok` `Result`type is
|
/// represented by the given network identifier, an `Ok` `Result`type is
|
||||||
/// returned. In the event of an error, a `NetworkError` is returned in the
|
/// returned. In the event of an error, a `NetworkError` is returned in the
|
||||||
/// `Result`. The `NetworkError` is then enumerated to a specific error type and
|
/// `Result`.
|
||||||
/// an appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> {
|
pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let disable = format!("DISABLE_NETWORK {}", id);
|
let disable = format!("DISABLE_NETWORK {}", id);
|
||||||
wpa.request(&disable).context(WpaCtrlRequest)?;
|
wpa.request(&disable)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -723,18 +661,12 @@ pub fn disable(id: &str, iface: &str) -> Result<(), NetworkError> {
|
||||||
///
|
///
|
||||||
/// If the network connection is successfully disconnected for the given
|
/// If the network connection is successfully disconnected for the given
|
||||||
/// wireless interface, an `Ok` `Result` type is returned. In the event of an
|
/// wireless interface, an `Ok` `Result` type is returned. In the event of an
|
||||||
/// error, a `NetworkError` is returned in the `Result`. The `NetworkError` is
|
/// error, a `NetworkError` is returned in the `Result`.
|
||||||
/// then enumerated to a specific error type and an appropriate JSON RPC
|
|
||||||
/// response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn disconnect(iface: &str) -> Result<(), NetworkError> {
|
pub fn disconnect(iface: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let disconnect = "DISCONNECT".to_string();
|
let disconnect = "DISCONNECT".to_string();
|
||||||
wpa.request(&disconnect).context(WpaCtrlRequest)?;
|
wpa.request(&disconnect)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -748,18 +680,12 @@ pub fn disconnect(iface: &str) -> Result<(), NetworkError> {
|
||||||
///
|
///
|
||||||
/// If the password is successfully updated for the access point represented by
|
/// If the password is successfully updated for the access point represented by
|
||||||
/// the given network identifier, an `Ok` `Result` type is returned. In the
|
/// the given network identifier, an `Ok` `Result` type is returned. In the
|
||||||
/// event of an error, a `NetworkError` is returned in the `Result`. The
|
/// event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// `NetworkError` is then enumerated to a specific error type and an
|
|
||||||
/// appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> {
|
pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
let new_pass = format!("NEW_PASSWORD {} {}", id, pass);
|
let new_pass = format!("NEW_PASSWORD {} {}", id, pass);
|
||||||
wpa.request(&new_pass).context(WpaCtrlRequest)?;
|
wpa.request(&new_pass)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,17 +697,11 @@ pub fn modify(id: &str, iface: &str, pass: &str) -> Result<(), NetworkError> {
|
||||||
///
|
///
|
||||||
/// If the network connection is successfully reassociated for the given
|
/// If the network connection is successfully reassociated for the given
|
||||||
/// wireless interface, an `Ok` `Result` type is returned. In the event of an
|
/// wireless interface, an `Ok` `Result` type is returned. In the event of an
|
||||||
/// error, a `NetworkError` is returned in the `Result`. The `NetworkError` is
|
/// error, a `NetworkError` is returned in the `Result`.
|
||||||
/// then enumerated to a specific error type and an appropriate JSON RPC
|
|
||||||
/// response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn reassociate(iface: &str) -> Result<(), NetworkError> {
|
pub fn reassociate(iface: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
wpa.request("REASSOCIATE")?;
|
||||||
.open()
|
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
wpa.request("REASSOCIATE").context(WpaCtrlRequest)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,13 +710,10 @@ pub fn reassociate(iface: &str) -> Result<(), NetworkError> {
|
||||||
/// If the reconfigure command is successfully executed, indicating a reread
|
/// If the reconfigure command is successfully executed, indicating a reread
|
||||||
/// of the `wpa_supplicant.conf` file by the `wpa_supplicant` process, an `Ok`
|
/// of the `wpa_supplicant.conf` file by the `wpa_supplicant` process, an `Ok`
|
||||||
/// `Result` type is returned. In the event of an error, a `NetworkError` is
|
/// `Result` type is returned. In the event of an error, a `NetworkError` is
|
||||||
/// returned in the `Result`. The `NetworkError` is then enumerated to a
|
/// returned in the `Result`.
|
||||||
/// specific error type and an appropriate JSON RPC response is sent to the
|
|
||||||
/// caller.
|
|
||||||
///
|
|
||||||
pub fn reconfigure() -> Result<(), NetworkError> {
|
pub fn reconfigure() -> Result<(), NetworkError> {
|
||||||
let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?;
|
let mut wpa = wpactrl::WpaCtrl::builder().open()?;
|
||||||
wpa.request("RECONFIGURE").context(WpaCtrlRequest)?;
|
wpa.request("RECONFIGURE")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,18 +725,12 @@ pub fn reconfigure() -> Result<(), NetworkError> {
|
||||||
///
|
///
|
||||||
/// If the network connection is successfully disconnected and reconnected for
|
/// If the network connection is successfully disconnected and reconnected for
|
||||||
/// the given wireless interface, an `Ok` `Result` type is returned. In the
|
/// the given wireless interface, an `Ok` `Result` type is returned. In the
|
||||||
/// event of an error, a `NetworkError` is returned in the `Result`. The
|
/// event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// `NetworkError` is then enumerated to a specific error type and an
|
|
||||||
/// appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn reconnect(iface: &str) -> Result<(), NetworkError> {
|
pub fn reconnect(iface: &str) -> Result<(), NetworkError> {
|
||||||
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
let wpa_path: String = format!("/var/run/wpa_supplicant/{}", iface);
|
||||||
let mut wpa = wpactrl::WpaCtrl::new()
|
let mut wpa = wpactrl::WpaCtrl::builder().ctrl_path(wpa_path).open()?;
|
||||||
.ctrl_path(wpa_path)
|
wpa.request("DISCONNECT")?;
|
||||||
.open()
|
wpa.request("RECONNECT")?;
|
||||||
.context(WpaCtrlOpen)?;
|
|
||||||
wpa.request("DISCONNECT").context(WpaCtrlRequest)?;
|
|
||||||
wpa.request("RECONNECT").context(WpaCtrlRequest)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,12 +738,9 @@ pub fn reconnect(iface: &str) -> Result<(), NetworkError> {
|
||||||
///
|
///
|
||||||
/// If wireless network configuration updates are successfully save to the
|
/// If wireless network configuration updates are successfully save to the
|
||||||
/// `wpa_supplicant.conf` file, an `Ok` `Result` type is returned. In the
|
/// `wpa_supplicant.conf` file, an `Ok` `Result` type is returned. In the
|
||||||
/// event of an error, a `NetworkError` is returned in the `Result`. The
|
/// event of an error, a `NetworkError` is returned in the `Result`.
|
||||||
/// `NetworkError` is then enumerated to a specific error type and an
|
|
||||||
/// appropriate JSON RPC response is sent to the caller.
|
|
||||||
///
|
|
||||||
pub fn save() -> Result<(), NetworkError> {
|
pub fn save() -> Result<(), NetworkError> {
|
||||||
let mut wpa = wpactrl::WpaCtrl::new().open().context(WpaCtrlOpen)?;
|
let mut wpa = wpactrl::WpaCtrl::builder().open()?;
|
||||||
wpa.request("SAVE_CONFIG").context(WpaCtrlRequest)?;
|
wpa.request("SAVE_CONFIG")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use snafu::ResultExt;
|
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::NetworkError;
|
||||||
|
|
||||||
/// Return matches for a given Regex pattern and text
|
/// Return matches for a given Regex pattern and text
|
||||||
///
|
///
|
||||||
|
@ -11,7 +10,7 @@ use crate::error::*;
|
||||||
/// * `text` - A string slice containing the text to be matched on
|
/// * `text` - A string slice containing the text to be matched on
|
||||||
///
|
///
|
||||||
pub fn regex_finder(pattern: &str, text: &str) -> Result<Option<String>, NetworkError> {
|
pub fn regex_finder(pattern: &str, text: &str) -> Result<Option<String>, NetworkError> {
|
||||||
let re = Regex::new(pattern).context(Regex)?;
|
let re = Regex::new(pattern)?;
|
||||||
let caps = re.captures(text);
|
let caps = re.captures(text);
|
||||||
let result = caps.map(|caps| caps[1].to_string());
|
let result = caps.map(|caps| caps[1].to_string());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue