From aba0057e9b7aa25ae05d2e30d6ebf556f54876c9 Mon Sep 17 00:00:00 2001 From: Lia Lenckowski Date: Mon, 12 Aug 2024 21:05:40 +0200 Subject: muffif will code --- Cargo.lock | 2 + Cargo.toml | 13 ++-- src/daemon.rs | 210 ++++++++++++++++++++++++++++++++++------------------------ src/main.rs | 1 + 4 files changed, 133 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 790dda5..31fd936 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,6 +490,7 @@ name = "mäsch" version = "0.1.0" dependencies = [ "atomic-write-file", + "base64", "clap", "dbus", "dbus-crossroads", @@ -498,6 +499,7 @@ dependencies = [ "env_logger", "futures", "log", + "rand", "serde", "serde_json", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 35fcdc4..1d1fb6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,17 +5,18 @@ edition = "2021" [dependencies] atomic-write-file = "0" +base64 = "0" clap = { version = "4.5.13", features = ["derive"] } +dbus = "0" +dbus-crossroads = "0" +dbus-tokio = "0" defguard_wireguard_rs = "0" env_logger = "0" +futures = "0" log = "0" +rand = "0" serde_json = "1" serde = { version = "1", features = ["derive"] } thiserror = "1" -xdg = "2" - tokio = { version = "1", features = ["full"] } # TODO features restricten -dbus = "0" -dbus-tokio = "0" -dbus-crossroads = "0" -futures = "0" +xdg = "2" 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, + hostfile: Option<(String, BTreeSet)>, } impl Drop for State { @@ -113,20 +116,7 @@ pub fn daemon() -> Result<(), DaemonError> { }; info!("read config"); - //let networks: HashMap = 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, - })?; - - 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(); - } - - state.apis.insert(name.clone(), wg); - + 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; + + let state = Arc::new(RwLock::new(state)); + + let rt = Builder::new_current_thread().enable_all().build()?; + rt.block_on(run_listeners(state))?; + + Ok(()) +} - if let Some((hosts_str, _)) = &hostfile { +fn add_network(state: &mut State, name: String, privkey: String, address: String, port: u16, peers: &HashMap) -> 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(); + } + + 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>) -> 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()); diff --git a/src/main.rs b/src/main.rs index c61306c..b7300a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ #![feature(let_chains)] #![feature(never_type)] +#![feature(if_let_guard)] pub mod daemon; -- cgit v1.2.3-70-g09d2