diff options
author | Lia Lenckowski <lialenck@protonmail.com> | 2024-08-13 16:31:39 +0200 |
---|---|---|
committer | Lia Lenckowski <lialenck@protonmail.com> | 2024-08-13 16:31:39 +0200 |
commit | 5073dc6ee88a02eb60f46127cbdb598692a42f39 (patch) | |
tree | c4c00358b7641f7d20886ba8acaa0a859636be7e | |
parent | 80c3c48d5cec4b227389fbc8fcbd10f2abf6bce1 (diff) | |
download | maesch-5073dc6ee88a02eb60f46127cbdb598692a42f39.tar maesch-5073dc6ee88a02eb60f46127cbdb598692a42f39.tar.bz2 maesch-5073dc6ee88a02eb60f46127cbdb598692a42f39.tar.zst |
clean exit on sigint/term/hup
-rw-r--r-- | src/daemon.rs | 96 |
1 files changed, 62 insertions, 34 deletions
diff --git a/src/daemon.rs b/src/daemon.rs index 34e4474..b5d1fc4 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -2,26 +2,31 @@ use atomic_write_file::AtomicWriteFile; use base64::prelude::*; use core::net::SocketAddr; use dbus::{channel::MatchingReceiver, message::MatchRule}; -use dbus_crossroads::{Crossroads, MethodErr, Context}; +use dbus_crossroads::{Context, Crossroads, MethodErr}; use defguard_wireguard_rs::{ host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi, }; -use futures::future; -use log::{debug, info, warn}; +use log::{debug, error, info, warn}; use rand::Rng; use serde::{Deserialize, Serialize}; use std::{ collections::{BTreeSet, HashMap}, fs::File, io::{ErrorKind, Read, Write}, - ops::DerefMut, - net::ToSocketAddrs, marker::PhantomData, + net::ToSocketAddrs, + ops::DerefMut, sync::Arc, time::SystemTime, }; use thiserror::Error; -use tokio::{net::TcpListener, runtime::Builder, sync::RwLock, task}; +use tokio::{ + net::TcpListener, + runtime::Builder, + signal::unix::{signal, SignalKind}, + sync::{broadcast, RwLock}, + task, +}; use xdg::BaseDirectories; use std::str::FromStr; @@ -150,15 +155,16 @@ pub fn daemon() -> Result<(), DaemonError> { })); let rt = Builder::new_current_thread().enable_all().build()?; - rt.block_on(init_networks(state))?; + rt.block_on(run_networks(state))?; Ok(()) } -async fn init_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { +async fn run_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { let mut state_rw_guard = state.write().await; let state_rw = state_rw_guard.deref_mut(); + // load existing configurations for (name, nw) in &state_rw.conf.networks { let wg_api = add_network( &mut state_rw.hostfile, @@ -167,10 +173,11 @@ async fn init_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { nw.address.clone(), nw.listen_port, &nw.peers, - ).await?; + ) + .await?; let addr = IpAddrMask::from_str(&nw.address)?.ip; - let h = task::spawn(make_fatal(run_network( + let h = task::spawn(print_error(run_network( state.clone(), TcpListener::bind((addr, nw.mäsch_port)).await?, name.clone(), @@ -183,9 +190,9 @@ async fn init_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { info!("loaded all existing configurations"); drop(state_rw_guard); + // set up dbus interface let mut cr = Crossroads::new(); let state_ref = state.clone(); - let if_token = cr.register("de.a.maesch", move |b| { b.signal::<(String, String), _>("Proposal", ("network", "peer_data")); b.method_with_cr_async( @@ -198,16 +205,20 @@ async fn init_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { }, ); }); - cr.insert("/de/a/maesch", &[if_token], ()); + // drive dbus interface let (res, c) = dbus_tokio::connection::new_system_sync()?; - cr.set_async_support(Some((c.clone(), Box::new(|x| { tokio::spawn(x); })))); - let _ = tokio::spawn(make_fatal(async { + cr.set_async_support(Some(( + c.clone(), + Box::new(|x| { + tokio::spawn(x); + }), + ))); + let _ = tokio::spawn(print_error(async { res.await; Result::<!, &'static str>::Err("lost connection to dbus!") })); - let receive_token = c.start_receive( MatchRule::new_method_call(), Box::new(move |msg, conn| { @@ -215,14 +226,31 @@ async fn init_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { true }), ); - c.request_name("de.a.maesch", false, true, false).await?; - future::pending::<!>().await + // wait for SIGTERM/SIGINT + let mut sigterm_fut = signal(SignalKind::terminate())?; + let mut sigint_fut = signal(SignalKind::interrupt())?; + let mut sighup_fut = signal(SignalKind::hangup())?; + + tokio::select! { + _ = sigterm_fut.recv() => info!("Received SIGTERM"), + _ = sigint_fut.recv() => info!("Received SIGINT"), + _ = sighup_fut.recv() => info!("Received SIGHUP"), + }; + + // clean exit + c.stop_receive(receive_token); + let mut state_rw_guard = state.write().await; + for (_, (wg_api, h)) in state_rw_guard.nw_handles.drain() { + let _ = wg_api.remove_interface(); + h.abort(); // could also join the handles... don't think that would do too much, though + } - //c.stop_receive(receive_token); + Ok(()) } +// TODO also take peers async fn handle_add_network( mut ctx: Context, state: Arc<RwLock<State>>, @@ -236,8 +264,8 @@ async fn handle_add_network( Ok(v) if v.len() == 32 => v.try_into().unwrap(), _ => { warn!("AddNetwork with bad key"); - return ctx.reply(Err(MethodErr::invalid_arg("bad key"))) - }, + return ctx.reply(Err(MethodErr::invalid_arg("bad key"))); + } }, }); @@ -248,8 +276,8 @@ async fn handle_add_network( Ok(ip_mask) => (ip_mask.ip, may_ip), Err(_) => { warn!("AddNetwork with bad ip"); - return ctx.reply(Err(MethodErr::invalid_arg("invalid ip"))) - }, + return ctx.reply(Err(MethodErr::invalid_arg("invalid ip"))); + } }, }; @@ -266,12 +294,14 @@ async fn handle_add_network( ip_string, lp, &HashMap::new(), - ).await { + ) + .await + { Ok(wg_api) => wg_api, Err(e) => { warn!("AddNetwork couldn't add network: {e}"); - return ctx.reply(Err(MethodErr::failed(&e))) - }, + return ctx.reply(Err(MethodErr::failed(&e))); + } }; // TODO ins wg_api @@ -280,10 +310,10 @@ async fn handle_add_network( Err(e) => { let _ = wg_api.remove_interface(); warn!("AddNetwork couldn't start listener: {e}"); - return ctx.reply(Err(MethodErr::failed(&e))) - }, + return ctx.reply(Err(MethodErr::failed(&e))); + } }; - let h = task::spawn(make_fatal(run_network( + let h = task::spawn(print_error(run_network( state.clone(), listener, name.clone(), @@ -291,6 +321,8 @@ async fn handle_add_network( state_rw.nw_handles.insert(name.clone(), (wg_api, h)); + // TODO save new config + ctx.reply(Ok((true,))) } @@ -371,15 +403,11 @@ async fn add_network( Ok(wg) } -async fn make_fatal<E: std::fmt::Display, O, F: std::future::Future<Output = Result<O, E>>>( +async fn print_error<E: std::fmt::Display, O, F: std::future::Future<Output = Result<O, E>>>( f: F, ) -> () { match f.await { - Err(e) => { - eprintln!("oh no: {e}"); - // TODO das soll lieber die tokio runtime beenden... - std::process::exit(1); - } + Err(e) => error!("oh no: {e}"), _ => (), }; } |