diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.rs | 39 | ||||
| -rw-r--r-- | src/error.rs | 12 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/main.rs | 3 | ||||
| -rw-r--r-- | src/network.rs | 2 | ||||
| -rw-r--r-- | src/test_macros.rs | 11 |
6 files changed, 58 insertions, 10 deletions
diff --git a/src/config.rs b/src/config.rs index d9dbe74..181f099 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use crate::dyndns_service::DynDnsProvider; use crate::error::{AppError, AppResult}; use crate::ip_service::IpServiceProvider; +use crate::network::get_active_network_adapters; use fqdn::FQDN; use log::warn; use serde::{Deserialize, Serialize}; @@ -50,6 +51,17 @@ impl Config { Err(AppError::ConfigFileNotProvided) } + + pub fn validate(self) -> AppResult<Self> { + let interfaces: Vec<String> = self.networks.iter().filter_map(|network| network.interface.clone()).collect(); + if !interfaces.is_empty() { + let adapters = get_active_network_adapters()?; + adapters.iter().find(|adapter| interfaces.contains(&adapter.name)) + .ok_or(AppError::UnableToFindNetworkInterface(interfaces.join(",")))?; + } + + Ok(self) + } } #[derive(Debug, Deserialize, Serialize)] @@ -80,6 +92,12 @@ pub struct DnsRecord { record_type: DnsRecordType, } +impl DnsRecord { + pub fn new(fqdn: FQDN) -> Self { + Self { fqdn, ttl: default_ttl(), record_type: default_record_type() } + } +} + fn default_record_type() -> DnsRecordType { DnsRecordType::A } @@ -92,10 +110,7 @@ mod tests { use super::*; use crate::dyndns_service::DynDnsProvider::Gandi; use crate::dyndns_service::gandi::GandiConfig; - use crate::{ - assert_config_file_not_found, assert_config_parse_error, assert_error, assert_io_error, - test, - }; + use crate::{assert_config_file_not_found, assert_config_parse_error, assert_error, assert_io_error, assert_unable_to_find_network_interface_error, test}; use serde_json::json; use std::fs::read_dir; use std::path::{Path, PathBuf}; @@ -190,4 +205,20 @@ mod tests { assert_io_error!(Config::load(vec![path.to_path_buf()])); } } + + test! { + fn unknown_network_interface() { + let config = Config { + networks: vec![WanConfig { + interface: Some("unknown0".to_string()), + dns_record: DnsRecord::new(FQDN::from_str("some.domain.com")?), + providers: vec![DynDnsProvider::Noop], + ip_service: IpServiceProvider::Noop, + }] + }; + + assert_unable_to_find_network_interface_error!(config.validate(), "unknown0"); + } + } + } diff --git a/src/error.rs b/src/error.rs index 1b71511..7d1700f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,7 +17,8 @@ pub enum AppError { InvalidResponse { url: Url, reason: String }, InvalidHttpHeader(String), UnableToGetHomeDirectory(GetHomeError), - NetworkInterfaceError(NetworkInterfaceError), + UnableToListNetworkInterfaces(NetworkInterfaceError), + UnableToFindNetworkInterface(String), } impl fmt::Display for AppError { @@ -43,8 +44,11 @@ impl fmt::Display for AppError { Self::UnableToGetHomeDirectory(err) => { write!(f, "Failed to get home directory: {}", err) } - Self::NetworkInterfaceError(err) => { - write!(f, "Network interface error: {}", err) + Self::UnableToListNetworkInterfaces(err) => { + write!(f, "Unable to list network interfaces: {}", err) + } + Self::UnableToFindNetworkInterface(err) => { + write!(f, "Unable to find network interface: {}", err) } } } @@ -56,7 +60,7 @@ impl std::error::Error for AppError { Self::IoError(err) => Some(err), Self::ConfigParseError { source, .. } => Some(source), Self::RequestFailed { source, .. } => Some(source), - Self::NetworkInterfaceError(err) => Some(err), + Self::UnableToListNetworkInterfaces(err) => Some(err), _ => None, } } @@ -3,6 +3,7 @@ mod dyndns_service; mod error; mod http; mod ip_service; +mod network; #[cfg(test)] #[macro_use] diff --git a/src/main.rs b/src/main.rs index 3db2582..e46b22d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use log::info; use reqwest::ClientBuilder; use std::path::PathBuf; use std::process::exit; +use crate::network::get_active_network_adapters; mod config; mod dyndns_service; @@ -76,7 +77,7 @@ async fn main() { } async fn run(args: Args) -> AppResult<()> { - let config = Config::load(args.get_config_files())?; + let config = Config::load(args.get_config_files())?.validate()?; let client = ClientBuilder::new().build()?; for network in config.networks { let ip = network.ip_service.resolve(&client).await?; diff --git a/src/network.rs b/src/network.rs index 3697e29..cd717a1 100644 --- a/src/network.rs +++ b/src/network.rs @@ -30,7 +30,7 @@ impl From<NetworkInterface> for NetworkAdapter { pub fn get_network_adapters() -> AppResult<Vec<NetworkAdapter>> { NetworkInterface::show() - .map_err(AppError::NetworkInterfaceError) + .map_err(AppError::UnableToListNetworkInterfaces) .map(|interfaces| interfaces.into_iter().map(NetworkAdapter::from).collect()) } diff --git a/src/test_macros.rs b/src/test_macros.rs index 7887647..9eb1467 100644 --- a/src/test_macros.rs +++ b/src/test_macros.rs @@ -50,6 +50,17 @@ macro_rules! assert_io_error { } #[macro_export] +macro_rules! assert_unable_to_find_network_interface_error { + ($result:expr, $expected_adapter:expr) => { + assert_error!($result, AppError::UnableToFindNetworkInterface(adapter) => { + assert_eq!(adapter, $expected_adapter, + "Expected network adapter {:?}, but got {:?}", + $expected_adapter, adapter); + }); + }; +} + +#[macro_export] macro_rules! assert_config_parse_error { ($result:expr, $expected_path:expr) => { assert_error!($result, AppError::ConfigParseError { path, source: _ } => { |
