summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLia Lenckowski <lialenck@protonmail.com>2024-08-12 21:05:40 +0200
committerLia Lenckowski <lialenck@protonmail.com>2024-08-12 21:05:40 +0200
commitaba0057e9b7aa25ae05d2e30d6ebf556f54876c9 (patch)
treec6789e3dd7ce6c5e6b2559253f789d2da1dd0702
parent4eb52cd5998235c2bffdbb4ebf8dac7e87f73888 (diff)
downloadmaesch-aba0057e9b7aa25ae05d2e30d6ebf556f54876c9.tar
maesch-aba0057e9b7aa25ae05d2e30d6ebf556f54876c9.tar.bz2
maesch-aba0057e9b7aa25ae05d2e30d6ebf556f54876c9.tar.zst
muffif will code
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml13
-rw-r--r--src/daemon.rs208
-rw-r--r--src/main.rs1
4 files changed, 132 insertions, 92 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<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());
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;