summaryrefslogtreecommitdiff
path: root/src/daemon.rs
diff options
context:
space:
mode:
authorLia Lenckowski <lialenck@protonmail.com>2024-08-10 00:46:45 +0200
committerLia Lenckowski <lialenck@protonmail.com>2024-08-10 00:46:45 +0200
commitc5ae944b3d0442cf8c0015d42e32c1ceea8d1c20 (patch)
tree30f2b29dbbb4f3d1b7829b5d2236ce09caa84305 /src/daemon.rs
parent1932a9c95174d7d211e19203df96a396107373f1 (diff)
downloadmaesch-c5ae944b3d0442cf8c0015d42e32c1ceea8d1c20.tar
maesch-c5ae944b3d0442cf8c0015d42e32c1ceea8d1c20.tar.bz2
maesch-c5ae944b3d0442cf8c0015d42e32c1ceea8d1c20.tar.zst
impl hostname ding; remove redb (deemed inefficient overkill)
we are not planning to be web-scale(tm) anyway
Diffstat (limited to 'src/daemon.rs')
-rw-r--r--src/daemon.rs158
1 files changed, 102 insertions, 56 deletions
diff --git a/src/daemon.rs b/src/daemon.rs
index 2c73d6c..1c746fd 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -1,9 +1,12 @@
+use atomic_write_file::AtomicWriteFile;
use core::net::SocketAddr;
use defguard_wireguard_rs::{host::Peer, InterfaceConfiguration, WGApi, WireguardInterfaceApi};
-use defguard_wireguard_rs::{key::Key as WgKey, net::IpAddrMask};
-use log::{info, trace, warn};
-use redb::{Database, Error, Key, Range, ReadableTable, TableDefinition, TypeName, Value};
+use defguard_wireguard_rs::{key::Key, net::IpAddrMask};
+use log::{info, warn};
use serde::{Deserialize, Serialize};
+use std::collections::BTreeSet;
+use std::fs::File;
+use std::io::{ErrorKind, Read, Write};
use std::net::{TcpListener, ToSocketAddrs};
use thiserror::Error;
use xdg::BaseDirectories;
@@ -18,15 +21,6 @@ pub enum DaemonError {
#[error("{0}")]
XdgBase(#[from] xdg::BaseDirectoriesError),
- #[error("{0}")]
- DbOpen(#[from] redb::DatabaseError),
- #[error("{0}")]
- DbTrans(#[from] redb::TransactionError),
- #[error("{0}")]
- DbTable(#[from] redb::TableError),
- #[error("{0}")]
- DbStorage(#[from] redb::StorageError),
-
// TODO hier wärs nett zu unterscheiden was decoded wurde
#[error("{0}")]
Decoding(#[from] serde_json::Error),
@@ -44,13 +38,12 @@ enum Endpoint {
// subset of defguard_wireguard_rs::host::Peer, with hostname added
#[derive(Serialize, Deserialize)]
struct PeerConfig {
- pubkey: WgKey,
- psk: Option<WgKey>,
- hostname: Option<String>,
- // if false: the hostname is kept around for sharing, but we personally do not use it
- use_hostname: bool,
+ pubkey: Key,
+ psk: Option<Key>,
+ ips: Vec<(IpAddrMask, Option<String>)>,
+ // if false: the hostnames are kept around for sharing, but we personally do not use them
+ use_hostnames: bool,
endpoint: Option<Endpoint>,
- ips: Vec<IpAddrMask>,
}
fn default_wg_port() -> u16 {
@@ -58,7 +51,8 @@ fn default_wg_port() -> u16 {
}
#[derive(Serialize, Deserialize)]
-struct InterfaceConfig {
+struct Network {
+ name: String,
privkey: String,
// this really should be a different type, but this is what defguard takes...
@@ -70,50 +64,66 @@ struct InterfaceConfig {
peers: Vec<PeerConfig>,
}
-// NOTE das ist ne dumme idee gewesen... nen peer hinzufügen braucht jz nen kompletten reserialize
-const NETWORKS: TableDefinition<&str, /* InterfaceConfig */ &[u8]> =
- TableDefinition::new("networks");
+#[derive(Serialize, Deserialize, Default)]
+struct Config {
+ networks: Vec<Network>,
+}
pub fn daemon() -> Result<(), DaemonError> {
- let db_path = BaseDirectories::with_prefix("mäsch")?.place_state_file("daemon-db")?;
- let db = Database::create(db_path)?;
- info!("opened db");
-
- let networks: Vec<(String, InterfaceConfig)> = match db.begin_read()?.open_table(NETWORKS) {
- Err(redb::TableError::TableDoesNotExist(_)) => vec![],
- Ok(tbl) => tbl
- .iter()?
- .map(|kv_result| {
- let (access_key, access_val) = kv_result?;
- Ok((
- access_key.value().to_owned(),
- serde_json::from_slice(access_val.value())?,
- ))
- })
- .collect::<Result<_, DaemonError>>()?,
- Err(e) => Err(e)?,
+ let config_path = BaseDirectories::with_prefix("mäsch")?.place_state_file("daemon.json")?;
+ let config: Config = match File::open(config_path) {
+ Ok(f) => serde_json::from_reader(f)?,
+ Err(e) => match e.kind() {
+ ErrorKind::NotFound => Config::default(),
+ _ => Err(e)?,
+ },
};
+ info!("read config");
- //let networks = vec![("kek".to_string(), InterfaceConfig {
+ //let networks = vec![Network {
+ // name: "kek".to_string(),
// privkey: "OK9WQudPVO5rXxcdxdtTzRmJzVu+KuqLMstYsZd8mWE=".to_string(),
// address: "1.2.3.4".to_string(),
// listen_port: 5221,
// peers: vec![PeerConfig {
- // pubkey: WgKey::from_str("Osrxi/bRVK+FQit7YMbIgSaOWmRDOZQoh/7ddV4eEE8=").unwrap(),
- // psk: Some(WgKey::from_str("wFiG3II9ivYBn+xjLGChC0PjNlbOibZ1K6pmspPD0Hg=").unwrap()),
- // hostname: Some("blah.blob".to_string()),
- // use_hostname: false,
+ // pubkey: Key::from_str("Osrxi/bRVK+FQit7YMbIgSaOWmRDOZQoh/7ddV4eEE8=").unwrap(),
+ // psk: Some(Key::from_str("wFiG3II9ivYBn+xjLGChC0PjNlbOibZ1K6pmspPD0Hg=").unwrap()),
+ // use_hostnames: true,
// endpoint: Some(Endpoint::Domain("alex.69owo.de".to_string(), 12456)),
- // ips: vec![IpAddrMask::from_str("5.4.3.2/24").unwrap()],
+ // ips: vec![(IpAddrMask::from_str("5.4.3.2/24").unwrap(), Some("blah.blub".to_owned()))],
// }],
- //})];
+ //}];
// TODO call wg.remove_interface on program exit using a drop impl on an 'Interface' struct
- // containing the InterfaceConfig and WGApi
- // TODO possibly add hostnames to /etc/hosts
- for (name, intr) in networks {
- let wg = WGApi::new(name.clone(), false)?;
- let defguard_peers = intr
+ // containing the Network and WGApi
+
+ let mut hostfile = match File::open("/etc/hosts") {
+ Ok(mut f) => {
+ let mut r = String::new();
+ f.read_to_string(&mut r)?;
+
+ let seen_hostnames: BTreeSet<String> = r
+ .lines()
+ .map(|l| {
+ l.split_whitespace()
+ .take_while(|dom| dom.chars().next().unwrap() != '#')
+ .skip(1)
+ })
+ .flatten()
+ .map(|dom| dom.to_owned())
+ .collect();
+
+ Some((r, seen_hostnames))
+ }
+ Err(e) => {
+ warn!("failed to read /etc/hosts: {e}");
+ None
+ }
+ };
+
+ for nw in config.networks {
+ let wg = WGApi::new(nw.name.clone(), false)?;
+ let defguard_peers = nw
.peers
.iter()
.map(|p| Peer {
@@ -136,18 +146,54 @@ pub fn daemon() -> Result<(), DaemonError> {
tx_bytes: 0,
rx_bytes: 0,
persistent_keepalive_interval: None,
- allowed_ips: p.ips.clone(),
+ allowed_ips: p.ips.iter().map(|(ip_mask, _)| ip_mask.clone()).collect(),
})
.collect();
wg.create_interface()?;
wg.configure_interface(&InterfaceConfiguration {
- name,
- prvkey: intr.privkey,
- address: intr.address,
- port: intr.listen_port as u32,
+ name: nw.name.clone(),
+ prvkey: nw.privkey,
+ address: nw.address,
+ port: nw.listen_port as u32,
peers: defguard_peers,
})?;
+
+ if let Some((hosts_str, hosts)) = &mut hostfile {
+ nw.peers
+ .iter()
+ .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 configuration for {0}", nw.name);
}
+ info!("loaded all existing configurations");
+
+ if let Some((hosts_str, _)) = &hostfile {
+ info!("proposed next hosts file: {hosts_str}");
+
+ let mut f = AtomicWriteFile::open("/etc/hosts")?;
+ f.write(hosts_str.as_bytes())?;
+ f.commit();
+ }
+
+ // TODO open dbus & network interfaces
Ok(())
}