summaryrefslogtreecommitdiff
path: root/src/daemon_dbus.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon_dbus.rs')
-rw-r--r--src/daemon_dbus.rs204
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,
},
);