diff options
author | Lia Lenckowski <lialenck@protonmail.com> | 2024-08-12 21:05:40 +0200 |
---|---|---|
committer | Lia Lenckowski <lialenck@protonmail.com> | 2024-08-12 21:05:40 +0200 |
commit | aba0057e9b7aa25ae05d2e30d6ebf556f54876c9 (patch) | |
tree | c6789e3dd7ce6c5e6b2559253f789d2da1dd0702 /src/daemon.rs | |
parent | 4eb52cd5998235c2bffdbb4ebf8dac7e87f73888 (diff) | |
download | maesch-aba0057e9b7aa25ae05d2e30d6ebf556f54876c9.tar maesch-aba0057e9b7aa25ae05d2e30d6ebf556f54876c9.tar.bz2 maesch-aba0057e9b7aa25ae05d2e30d6ebf556f54876c9.tar.zst |
muffif will code
Diffstat (limited to 'src/daemon.rs')
-rw-r--r-- | src/daemon.rs | 208 |
1 files changed, 122 insertions, 86 deletions
diff --git a/src/daemon.rs b/src/daemon.rs index 220c286..ab84f03 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,15 +1,17 @@ use atomic_write_file::AtomicWriteFile; +use base64::prelude::*; use core::net::SocketAddr; use dbus::{channel::MatchingReceiver, message::MatchRule}; -use dbus_crossroads::Crossroads; +use dbus_crossroads::{Crossroads, MethodErr}; use defguard_wireguard_rs::{ host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi, }; use futures::future; use log::{info, warn}; +use rand::Rng; use serde::{Deserialize, Serialize}; use std::{ - collections::{HashMap, BTreeSet}, + collections::{BTreeSet, HashMap}, fs::File, io::{ErrorKind, Read, Write}, net::ToSocketAddrs, @@ -92,6 +94,7 @@ struct Config { struct State { conf: Config, apis: HashMap<String, WGApi>, + hostfile: Option<(String, BTreeSet<String>)>, } impl Drop for State { @@ -113,20 +116,7 @@ pub fn daemon() -> Result<(), DaemonError> { }; info!("read config"); - //let networks: HashMap<String, Network> = vec![("kek".to_owned(), Network { - // privkey: "OK9WQudPVO5rXxcdxdtTzRmJzVu+KuqLMstYsZd8mWE=".to_string(), - // address: "1.2.3.4".to_string(), - // listen_port: 5221, - // peers: vec![PeerConfig { - // pubkey: Key::from_str("Osrxi/bRVK+FQit7YMbIgSaOWmRDOZQoh/7ddV4eEE8=").unwrap(), - // psk: Some(Key::from_str("wFiG3II9ivYBn+xjLGChC0PjNlbOibZ1K6pmspPD0Hg=").unwrap()), - // use_hostnames: false, - // endpoint: Some(Endpoint::Domain("alex.69owo.de".to_string(), 12456)), - // ips: vec![(IpAddrMask::from_str("5.4.3.2/24").unwrap(), Some("blah.blub".to_owned()))], - // }], - //})].into_iter().collect(); - - let mut hostfile = match File::open("/etc/hosts") { + let hostfile = match File::open("/etc/hosts") { Ok(mut f) => { let mut r = String::new(); f.read_to_string(&mut r)?; @@ -151,77 +141,88 @@ pub fn daemon() -> Result<(), DaemonError> { }; let mut state = State { - conf: config, + conf: Config::default(), apis: HashMap::new(), + hostfile, }; - for (name, nw) in &state.conf.networks { - let wg = WGApi::new(name.clone(), false)?; - let defguard_peers = nw - .peers - .iter() - .map(|(peer_key, p)| Peer { - public_key: peer_key.clone(), - preshared_key: p.psk.clone(), - protocol_version: None, - endpoint: p - .endpoint - .clone() - .map(|e| match e { - Endpoint::Ip(ep) => Some(ep), - Endpoint::Domain(s, p) => (s, p) - .to_socket_addrs() - .ok() - .map(|mut it| it.next()) - .flatten(), - }) - .flatten(), - last_handshake: None, - tx_bytes: 0, - rx_bytes: 0, - persistent_keepalive_interval: None, - allowed_ips: p.ips.iter().map(|(ip_mask, _)| ip_mask.clone()).collect(), - }) - .collect(); - wg.create_interface()?; - wg.configure_interface(&InterfaceConfiguration { - name: name.clone(), - prvkey: nw.privkey.clone(), - address: nw.address.clone(), - port: nw.listen_port as u32, - peers: defguard_peers, - })?; + for (name, nw) in &config.networks { + add_network(&mut state, name.clone(), nw.privkey.clone(), nw.address.clone(), nw.listen_port, &nw.peers)?; + info!("loaded configuration for {0}", name); + } + info!("loaded all existing configurations"); + state.conf = config; - if let Some((hosts_str, hosts)) = &mut hostfile { - nw.peers - .values() - .map(|peer| { - if peer.use_hostnames { - peer.ips - .iter() - .map(|(mask, may_dom)| { - if let Some(dom) = may_dom - && hosts.insert(dom.clone()) - { - hosts_str.push_str(&format!("{}", mask.ip)); - hosts_str.push('\t'); - hosts_str.push_str(&dom); - hosts_str.push('\n'); - } - }) - .count(); - } - }) - .count(); - } + let state = Arc::new(RwLock::new(state)); - state.apis.insert(name.clone(), wg); + let rt = Builder::new_current_thread().enable_all().build()?; + rt.block_on(run_listeners(state))?; - info!("loaded configuration for {0}", name); + Ok(()) +} + +fn add_network(state: &mut State, name: String, privkey: String, address: String, port: u16, peers: &HashMap<Key, PeerConfig>) -> Result<(), DaemonError> { + let wg = WGApi::new(name.clone(), false)?; + let defguard_peers = peers + .iter() + .map(|(peer_key, p)| Peer { + public_key: peer_key.clone(), + preshared_key: p.psk.clone(), + protocol_version: None, + endpoint: p + .endpoint + .clone() + .map(|e| match e { + Endpoint::Ip(ep) => Some(ep), + Endpoint::Domain(s, p) => (s, p) + .to_socket_addrs() + .ok() + .map(|mut it| it.next()) + .flatten(), + }) + .flatten(), + last_handshake: None, + tx_bytes: 0, + rx_bytes: 0, + persistent_keepalive_interval: None, + allowed_ips: p.ips.iter().map(|(ip_mask, _)| ip_mask.clone()).collect(), + }) + .collect(); + wg.create_interface()?; + wg.configure_interface(&InterfaceConfiguration { + name: name.clone(), + prvkey: privkey, + address: address, + port: port as u32, + peers: defguard_peers, + })?; + + if let Some((hosts_str, hosts)) = &mut state.hostfile { + peers + .values() + .map(|peer| { + if peer.use_hostnames { + peer.ips + .iter() + .map(|(mask, may_dom)| { + if let Some(dom) = may_dom + && hosts.insert(dom.clone()) + { + hosts_str.push_str(&format!("{}", mask.ip)); + hosts_str.push('\t'); + hosts_str.push_str(&dom); + hosts_str.push('\n'); + } + }) + .count(); + } + }) + .count(); } - info!("loaded all existing configurations"); - if let Some((hosts_str, _)) = &hostfile { + state.apis.insert(name, wg); + + if let Some((hosts_str, _)) = &state.hostfile { info!("proposed next hosts file: {hosts_str}"); let mut f = AtomicWriteFile::open("/etc/hosts")?; @@ -229,11 +230,6 @@ pub fn daemon() -> Result<(), DaemonError> { f.commit()?; } - let state = Arc::new(RwLock::new(state)); - - let rt = Builder::new_current_thread().enable_all().build()?; - rt.block_on(run_listeners(state))?; - Ok(()) } @@ -250,9 +246,49 @@ async fn run_listeners(state: Arc<RwLock<State>>) -> Result<(), DaemonError> { } let mut cr = Crossroads::new(); - let if_token = cr.register("de.69owo.maesch", |b| { + let state_ref = state.clone(); + + let if_token = cr.register("de.69owo.maesch", move |b| { + let state_ref = state_ref.clone(); + b.signal::<(String, String), _>("Proposal", ("network", "peer_data")); - //b.method_with_cr_async("MigrateQuick"); + b.method_with_cr_async("AddNetwork", + ("name", "key", "ip", "listen_port", "maesch_port"), + ("success",), move |mut ctx, cr, (name, may_key, may_ip, may_lp, may_mp): (String, String, String, u16, u16)| async move + { + // 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(), + _ => 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) { + Err(_) => return ctx.reply(Err(MethodErr::invalid_arg("invalid ip"))), + Ok(ip_mask) => (ip_mask.ip, may_ip), + }, + }; + + let lp = if may_lp == 0 { 25565 } else { may_lp }; + let mp = if may_mp == 0 { 51820 } else { may_mp }; + + let mut st_wr = state_ref.write().await; + + match add_network(&mut st_wr, name, key.to_string(), ip_string, lp, &HashMap::new()) { + Ok(_) => (), + Err(e) => return ctx.reply(Err(MethodErr::failed(&e))), + }; + + //let listener = TcpListener::bind((ip, mp)).await?; + + ctx.reply(Ok((true,))) + }); }); cr.insert("/de/69owo/maesch", &[if_token], state.clone()); |