From 2c31a4b6ec950e7d3a26abf2a32f91b2819894f1 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Tue, 23 Nov 2021 23:07:57 -0700 Subject: [PATCH] client: run 'up' on all interfaces when none is specified --- client/src/main.rs | 24 +++++++++++++++++------- client/src/util.rs | 30 ++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/client/src/main.rs b/client/src/main.rs index 82011c5..535d6ed 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -32,6 +32,8 @@ use nat::NatTraverse; use shared::{wg, Error}; use util::{human_duration, human_size, Api}; +use crate::util::all_installed; + struct PeerState<'a> { peer: &'a Peer, info: Option<&'a PeerInfo>, @@ -131,7 +133,7 @@ enum Command { #[structopt(flatten)] nat: NatOpts, - interface: Interface, + interface: Option, }, /// Fetch and update your local interface with the latest peer list @@ -421,7 +423,7 @@ fn redeem_invite( target_conf: PathBuf, network: NetworkOpts, ) -> Result<(), Error> { - log::info!("bringing up the interface."); + log::info!("bringing up interface {}.", iface.as_str_lossy().yellow()); let resolved_endpoint = config .server .external_endpoint @@ -474,14 +476,22 @@ fn redeem_invite( } fn up( - interface: &InterfaceName, + interface: Option, opts: &Opts, loop_interval: Option, hosts_path: Option, nat: &NatOpts, ) -> Result<(), Error> { loop { - fetch(interface, opts, true, hosts_path.clone(), nat)?; + let interfaces = match &interface { + Some(iface) => vec![iface.clone()], + None => all_installed(&opts.config_dir)?, + }; + + for iface in interfaces { + fetch(&*iface, opts, true, hosts_path.clone(), nat)?; + } + match loop_interval { Some(interval) => thread::sleep(interval), None => break, @@ -512,7 +522,7 @@ fn fetch( ); } - log::info!("bringing up the interface."); + log::info!("bringing up interface {}.", interface.as_str_lossy().yellow()); let resolved_endpoint = config .server .external_endpoint @@ -533,7 +543,7 @@ fn fetch( .with_str(interface.to_string())?; } - log::info!("fetching state from server..."); + log::info!("fetching state for {} from server...", interface.as_str_lossy().yellow()); let mut store = DataStore::open_or_create(&opts.data_dir, interface)?; let api = Api::new(&config.server); let State { peers, cidrs } = api.http("GET", "/user/state")?; @@ -1158,7 +1168,7 @@ fn run(opts: &Opts) -> Result<(), Error> { nat, interval, } => up( - &interface, + interface, opts, daemon.then(|| Duration::from_secs(interval)), hosts.into(), diff --git a/client/src/util.rs b/client/src/util.rs index cabd137..79772ad 100644 --- a/client/src/util.rs +++ b/client/src/util.rs @@ -3,8 +3,8 @@ use colored::*; use indoc::eprintdoc; use log::{Level, LevelFilter}; use serde::{de::DeserializeOwned, Serialize}; -use shared::{interface_config::ServerInfo, PeerDiff, INNERNET_PUBKEY_HEADER}; -use std::{io, path::Path, time::Duration}; +use shared::{interface_config::ServerInfo, PeerDiff, INNERNET_PUBKEY_HEADER, Interface}; +use std::{io, path::Path, time::Duration, ffi::OsStr}; use ureq::{Agent, AgentBuilder}; static LOGGER: Logger = Logger; @@ -170,6 +170,32 @@ pub fn print_peer_diff(store: &DataStore, diff: &PeerDiff) { } } +pub fn all_installed(config_dir: &Path) -> Result, std::io::Error> { + // All errors are bubbled up when enumerating a directory + let entries: Vec<_> = std::fs::read_dir(config_dir)? + .into_iter() + .collect::>()?; + + let installed: Vec<_> = entries.into_iter() + .filter(|entry| match entry.file_type() { + Ok(f) => f.is_file(), + _ => false + }) + .filter_map(|entry| { + let path = entry.path(); + match (path.extension(), path.file_stem()) { + (Some(extension), Some(stem)) if extension == OsStr::new("conf") => { + Some(stem.to_string_lossy().to_string()) + } + _ => None + } + }) + .map(|name| name.parse()) + .collect::>()?; + + Ok(installed) +} + pub struct Api<'a> { agent: Agent, server: &'a ServerInfo,