diff options
author | Lia Lenckowski <lialenck@protonmail.com> | 2024-08-16 23:29:59 +0200 |
---|---|---|
committer | Lia Lenckowski <lialenck@protonmail.com> | 2024-08-16 23:29:59 +0200 |
commit | d14c230f63617bb5fe84414723c10842fc029a3c (patch) | |
tree | 611d286d27f6605bb7b63667f221ccc7f7b19495 /src/daemon_dbus.rs | |
parent | 9c9039bdcd3f829ff0cfee5153b0435e0d209114 (diff) | |
download | maesch-d14c230f63617bb5fe84414723c10842fc029a3c.tar maesch-d14c230f63617bb5fe84414723c10842fc029a3c.tar.bz2 maesch-d14c230f63617bb5fe84414723c10842fc029a3c.tar.zst |
add AddPeer
Diffstat (limited to 'src/daemon_dbus.rs')
-rw-r--r-- | src/daemon_dbus.rs | 204 |
1 files changed, 198 insertions, 6 deletions
diff --git a/src/daemon_dbus.rs b/src/daemon_dbus.rs index f0873f0..5615bab 100644 --- a/src/daemon_dbus.rs +++ b/src/daemon_dbus.rs @@ -8,8 +8,14 @@ use defguard_wireguard_rs::{key::Key, net::IpAddrMask, WireguardInterfaceApi}; use log::{debug, error, info, warn}; use rand::Rng; use std::{ - collections::HashMap, marker::PhantomData, ops::DerefMut, path::PathBuf, str::FromStr, + collections::{hash_map::Entry, HashMap}, + marker::PhantomData, + net::SocketAddr, + ops::DerefMut, + path::PathBuf, + str::FromStr, sync::Arc, + time::SystemTime, }; use tokio::{net::TcpListener, sync::RwLock, task}; @@ -26,6 +32,9 @@ pub async fn start_dbus( let state_rem_network = state.clone(); let config_path_rem_network = config_path.clone(); + let state_add_peer = state.clone(); + let config_path_add_peer = config_path.clone(); + b.method_with_cr_async( "AddNetwork", ("name", "key", "ip", "listen_port", "maesch_port"), @@ -49,6 +58,38 @@ pub async fn start_dbus( ) }, ); + b.method_with_cr_async( + "AddPeer", + ( + "network", + "key", + "psk", + "use_hostnames", + "endpoint", + "maesch_endpoint", + "ips", + ), + ("success",), + move |ctx, + _, + args: ( + String, + String, + String, + bool, + String, + String, + Vec<(String, String)>, + )| { + debug!("Received AddPeer"); + handle_add_peer( + ctx, + state_add_peer.clone(), + config_path_add_peer.clone(), + args, + ) + }, + ); }); cr.insert("/de/a/maesch", &[if_token], ()); @@ -76,7 +117,155 @@ pub async fn start_dbus( Ok((c, receive_token)) } -pub async fn handle_remove_network( +async fn handle_add_peer( + mut ctx: Context, + state: Arc<RwLock<State>>, + config_path: PathBuf, + (nw_name, key, may_psk, use_hostnames, may_endpoint, may_mäsch_endpoint, allowed_ips): ( + String, + String, + String, + bool, + String, + String, + Vec<(String, String)>, + ), +) -> PhantomData<(bool,)> { + let key = match Key::from_str(&key) { + Ok(k) => k, + Err(e) => { + warn!("AddPeer with bad key: {e}"); + return ctx.reply(Err(MethodErr::invalid_arg(&e))); + } + }; + + let psk = match may_psk.as_str() { + "" => None, + _ => match Key::from_str(&may_psk) { + Ok(k) => Some(k), + Err(e) => { + warn!("AddPeer with bad pre-shared key: {e}"); + return ctx.reply(Err(MethodErr::invalid_arg(&e))); + } + }, + }; + + // use_hostnames is already a boolean, so i guess we require it to be set? + + let endpoint = match may_endpoint.as_str() { + "" => None, + _ => match SocketAddr::from_str(&may_endpoint) { + Ok(addr) => Some(Endpoint::Ip(addr)), + Err(_) => { + let mut parts_it = may_endpoint.split(':'); + match (parts_it.next(), parts_it.next(), parts_it.next()) { + (Some(domain), Some(port), None) if let Ok(port) = port.parse() => { + Some(Endpoint::Domain(domain.to_owned(), port)) + } + _ => { + warn!("AddPeer with bad endpoint: {may_endpoint}"); + return ctx.reply(Err(MethodErr::invalid_arg("Could not parse endpoint"))); + } + } + } + }, + }; + + let mäsch_endpoint = match SocketAddr::from_str(&may_mäsch_endpoint) { + Ok(addr) => addr, + Err(e) => { + warn!("AddPeer with bad mäsch endpoint: {e}"); + return ctx.reply(Err(MethodErr::invalid_arg(&e))); + } + }; + + // let may_allowed_ips = mapM (\(addr, hostname) -> (, if hostname == "" then Nothing else Just hostname) <$> readMaybe addr) allowed_ips + let may_allowed_ips: Result<Vec<(IpAddrMask, Option<String>)>, _> = allowed_ips + .into_iter() + .map(|(addr, hostname)| { + addr.parse() + .map(|ip_mask| (ip_mask, if hostname == "" { None } else { Some(hostname) })) + }) + .collect(); + let allowed_ips = match may_allowed_ips { + Ok(v) => v, + Err(e) => { + warn!("AddPeer with bad allowed ips: {e}"); + return ctx.reply(Err(MethodErr::invalid_arg(&e))); + } + }; + + let mut state_rw_guard = state.write().await; + if !state_rw_guard.conf.networks.contains_key(&nw_name) { + warn!("AddPeer for non-existent network"); + return ctx.reply(Err(MethodErr::invalid_arg("bad network"))); + }; + + let allowed_ips_without_domains = allowed_ips.iter().map(|(ip, _)| ip.clone()).collect(); + + let wg_api = &state_rw_guard + .nw_handles + .get(&nw_name) + .expect("state.conf.networks and state.nw_handles desynced") + .0; + match add_peer( + wg_api, + key.clone(), + psk.clone(), + endpoint.clone(), + allowed_ips_without_domains, + ) + .await + { + Ok(_) => info!("Added peer"), + Err(e) => { + warn!("AddPeer failed: {e}"); + return ctx.reply(Err(MethodErr::invalid_arg(&e))); + } + }; + + match state_rw_guard + .conf + .networks + .get_mut(&nw_name) + .expect("state.conf.networks changed while lock was held") + .peers + .entry(key) + { + Entry::Vacant(e) => { + e.insert(PeerConfig { + psk, + ips: allowed_ips, + use_hostnames, + endpoint, + last_changed: SystemTime::now(), + known_to: vec![], + mäsch_endpoint, + }); + } + Entry::Occupied(e) => { + let r = e.into_mut(); + r.psk = psk; + r.ips = allowed_ips; + r.use_hostnames = use_hostnames; + r.endpoint = endpoint; + r.last_changed = SystemTime::now(); + r.mäsch_endpoint = mäsch_endpoint; + } + }; + + match write_config(&state_rw_guard.conf, &config_path) { + Ok(_) => info!("Synced config"), + Err(e) => { + error!("Couldn't sync config: {e}"); + return ctx.reply(Err(MethodErr::failed(&e))); + } + }; + + return ctx.reply(Ok((true,))); +} + +async fn handle_remove_network( mut ctx: Context, state: Arc<RwLock<State>>, config_path: PathBuf, @@ -118,8 +307,7 @@ pub async fn handle_remove_network( ctx.reply(Ok((true,))) } -// TODO make this merge correctly... -pub async fn handle_add_network( +async fn handle_add_network( mut ctx: Context, state: Arc<RwLock<State>>, config_path: PathBuf, @@ -128,7 +316,7 @@ pub async fn handle_add_network( let mut state_rw_guard = state.write().await; let state_rw = state_rw_guard.deref_mut(); - // TODO do more with the entry... + // Scary! let prev_entry = state_rw.conf.networks.remove(&name); let key = if may_key.as_str() == "" { @@ -151,6 +339,7 @@ pub async fn handle_add_network( ), None => { warn!("AddNetwork with no ip"); + prev_entry.map(|pe| state_rw.conf.networks.insert(name, pe)); return ctx.reply(Err(MethodErr::invalid_arg("ip required"))); } }, @@ -158,6 +347,7 @@ pub async fn handle_add_network( Ok(ip_mask) => (ip_mask.ip, may_ip), Err(_) => { warn!("AddNetwork with bad ip"); + prev_entry.map(|pe| state_rw.conf.networks.insert(name, pe)); return ctx.reply(Err(MethodErr::invalid_arg("invalid ip"))); } }, @@ -189,6 +379,7 @@ pub async fn handle_add_network( Ok(v) => v, Err(e) => { warn!("AddNetwork couldn't add network: {e}"); + prev_entry.map(|pe| state_rw.conf.networks.insert(name, pe)); return ctx.reply(Err(MethodErr::failed(&e))); } }; @@ -198,6 +389,7 @@ pub async fn handle_add_network( Err(e) => { let _ = wg_api.remove_interface(); warn!("AddNetwork couldn't start listener: {e}"); + prev_entry.map(|pe| state_rw.conf.networks.insert(name, pe)); return ctx.reply(Err(MethodErr::failed(&e))); } }; @@ -214,7 +406,7 @@ pub async fn handle_add_network( privkey: key, address: ip_string, listen_port: lp, - peers: prev_entry.map_or_else(|| HashMap::new(), |nw| nw.peers), + peers: prev_entry.map_or_else(|| HashMap::new(), |nw: Network| nw.peers), mäsch_port: mp, }, ); |