use base64::prelude::*; use dbus::{channel::MatchingReceiver, message::MatchRule}; use dbus_crossroads::{Context, Crossroads, MethodErr}; use defguard_wireguard_rs::{ host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi, }; use log::{debug, error, info, warn}; use rand::Rng; use std::{ collections::{BTreeSet, HashMap}, marker::PhantomData, ops::DerefMut, str::FromStr, sync::Arc, }; use tokio::{ net::TcpListener, sync::{broadcast, RwLock}, task, }; use crate::{daemon::*, daemon_network::*}; // TODO also take peers pub async fn handle_add_network( mut ctx: Context, state: Arc>, (name, may_key, may_ip, may_lp, may_mp): (String, String, String, u16, u16), ) -> PhantomData<(bool,)> { // NOTE: this is kinda stupid: we convert to a string later anyways, as thats what // defguard_wg takes... let key = Key::new(match may_key.as_str() { "" => rand::thread_rng().gen(), _ => match BASE64_STANDARD.decode(may_key) { Ok(v) if v.len() == 32 => v.try_into().unwrap(), _ => { warn!("AddNetwork with bad key"); return ctx.reply(Err(MethodErr::invalid_arg("bad key"))); } }, }); // we store the ip as the original string, but should validate it regardless let (ip, ip_string) = match may_ip.as_str() { "" => todo!(), _ => match IpAddrMask::from_str(&may_ip) { Ok(ip_mask) => (ip_mask.ip, may_ip), Err(_) => { warn!("AddNetwork with bad ip"); return ctx.reply(Err(MethodErr::invalid_arg("invalid ip"))); } }, }; let lp = if may_lp == 0 { 25565 } else { may_lp }; let mp = if may_mp == 0 { 51820 } else { may_mp }; let mut state_rw_guard = state.write().await; let state_rw = state_rw_guard.deref_mut(); let wg_api = match add_network( &mut state_rw.hostfile, name.clone(), key.to_string(), ip_string, lp, &HashMap::new(), ) .await { Ok(wg_api) => wg_api, Err(e) => { warn!("AddNetwork couldn't add network: {e}"); return ctx.reply(Err(MethodErr::failed(&e))); } }; // TODO ins wg_api let listener = match TcpListener::bind((ip, mp)).await { Ok(l) => l, Err(e) => { let _ = wg_api.remove_interface(); warn!("AddNetwork couldn't start listener: {e}"); return ctx.reply(Err(MethodErr::failed(&e))); } }; let h = task::spawn(print_error(run_network( state.clone(), listener, name.clone(), ))); state_rw.nw_handles.insert(name.clone(), (wg_api, h)); // TODO save new config ctx.reply(Ok((true,))) }