diff options
Diffstat (limited to 'src/daemon.rs')
-rw-r--r-- | src/daemon.rs | 143 |
1 files changed, 141 insertions, 2 deletions
diff --git a/src/daemon.rs b/src/daemon.rs index c88912f..2c73d6c 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,14 +1,153 @@ -use std::net::TcpListener; +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 serde::{Deserialize, Serialize}; +use std::net::{TcpListener, ToSocketAddrs}; use thiserror::Error; +use xdg::BaseDirectories; + +use std::str::FromStr; #[derive(Debug, Error)] pub enum DaemonError { #[error("{0}")] Io(#[from] std::io::Error), + + #[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), + + #[error("{0}")] + WgInterfaceError(#[from] defguard_wireguard_rs::error::WireguardInterfaceError), +} + +#[derive(Serialize, Deserialize, Clone)] +enum Endpoint { + Ip(SocketAddr), + Domain(String, u16), } +// 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, + endpoint: Option<Endpoint>, + ips: Vec<IpAddrMask>, +} + +fn default_wg_port() -> u16 { + 51820 +} + +#[derive(Serialize, Deserialize)] +struct InterfaceConfig { + privkey: String, + + // this really should be a different type, but this is what defguard takes... + address: String, + + #[serde(default = "default_wg_port")] + listen_port: u16, + + 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"); + pub fn daemon() -> Result<(), DaemonError> { - let listener = TcpListener::bind("0.0.0.0")?; // TODO + 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 networks = vec![("kek".to_string(), InterfaceConfig { + // 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, + // endpoint: Some(Endpoint::Domain("alex.69owo.de".to_string(), 12456)), + // ips: vec![IpAddrMask::from_str("5.4.3.2/24").unwrap()], + // }], + //})]; + + // 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 + .peers + .iter() + .map(|p| Peer { + public_key: p.pubkey.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.clone(), + }) + .collect(); + wg.create_interface()?; + wg.configure_interface(&InterfaceConfiguration { + name, + prvkey: intr.privkey, + address: intr.address, + port: intr.listen_port as u32, + peers: defguard_peers, + })?; + } Ok(()) } |