summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/daemon.rs214
-rw-r--r--src/daemon_dbus.rs98
-rw-r--r--src/daemon_network.rs102
-rw-r--r--src/main.rs2
4 files changed, 226 insertions, 190 deletions
diff --git a/src/daemon.rs b/src/daemon.rs
index b5d1fc4..bf6105c 100644
--- a/src/daemon.rs
+++ b/src/daemon.rs
@@ -1,5 +1,3 @@
-use atomic_write_file::AtomicWriteFile;
-use base64::prelude::*;
use core::net::SocketAddr;
use dbus::{channel::MatchingReceiver, message::MatchRule};
use dbus_crossroads::{Context, Crossroads, MethodErr};
@@ -7,7 +5,6 @@ use defguard_wireguard_rs::{
host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi,
};
use log::{debug, error, info, warn};
-use rand::Rng;
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeSet, HashMap},
@@ -16,6 +13,7 @@ use std::{
marker::PhantomData,
net::ToSocketAddrs,
ops::DerefMut,
+ str::FromStr,
sync::Arc,
time::SystemTime,
};
@@ -29,7 +27,7 @@ use tokio::{
};
use xdg::BaseDirectories;
-use std::str::FromStr;
+use crate::{daemon_dbus::*, daemon_network::*};
#[derive(Debug, Error)]
pub enum DaemonError {
@@ -54,24 +52,24 @@ pub enum DaemonError {
}
#[derive(Serialize, Deserialize, Clone)]
-enum Endpoint {
+pub enum Endpoint {
Ip(SocketAddr),
Domain(String, u16),
}
// subset of defguard_wireguard_rs::host::Peer, with hostname added
#[derive(Serialize, Deserialize)]
-struct PeerConfig {
- psk: Option<Key>,
- ips: Vec<(IpAddrMask, Option<String>)>,
+pub struct PeerConfig {
+ pub psk: Option<Key>,
+ pub 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>,
+ pub use_hostnames: bool,
+ pub endpoint: Option<Endpoint>,
- last_changed: SystemTime,
- known_to: Vec<usize>,
+ pub last_changed: SystemTime,
+ pub known_to: Vec<usize>,
- mäsch_endpoint: SocketAddr,
+ pub mäsch_endpoint: SocketAddr,
}
fn default_wg_port() -> u16 {
@@ -79,30 +77,27 @@ fn default_wg_port() -> u16 {
}
#[derive(Serialize, Deserialize)]
-struct Network {
- privkey: String,
-
+pub struct Network {
+ pub privkey: String,
// this really should be a different type, but this is what defguard takes...
- address: String,
-
+ pub address: String,
#[serde(default = "default_wg_port")]
- listen_port: u16,
-
- peers: HashMap<Key, PeerConfig>,
+ pub listen_port: u16,
+ pub peers: HashMap<Key, PeerConfig>,
- mäsch_port: u16,
+ pub mäsch_port: u16,
}
#[derive(Serialize, Deserialize, Default)]
-struct Config {
- networks: HashMap<String, Network>,
+pub struct Config {
+ pub networks: HashMap<String, Network>,
}
// TODO das überschreibt änderungen an /etc/hosts während der runtime :(
-struct State {
- conf: Config,
- nw_handles: HashMap<String, (WGApi, task::JoinHandle<()>)>,
- hostfile: Option<(String, BTreeSet<String>)>,
+pub struct State {
+ pub conf: Config,
+ pub nw_handles: HashMap<String, (WGApi, task::JoinHandle<()>)>,
+ pub hostfile: Option<(String, BTreeSet<String>)>,
}
impl Drop for State {
@@ -250,160 +245,7 @@ async fn run_networks(state: Arc<RwLock<State>>) -> Result<(), DaemonError> {
Ok(())
}
-// TODO also take peers
-async fn handle_add_network(
- mut ctx: Context,
- state: Arc<RwLock<State>>,
- (name, may_key, may_ip, may_lp, may_mp): (String, String, String, u16, u16),
-) -> PhantomData<(bool,)> {
- // 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(),
- _ => {
- warn!("AddNetwork with bad key");
- 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) {
- Ok(ip_mask) => (ip_mask.ip, may_ip),
- Err(_) => {
- warn!("AddNetwork with bad ip");
- return ctx.reply(Err(MethodErr::invalid_arg("invalid ip")));
- }
- },
- };
-
- let lp = if may_lp == 0 { 25565 } else { may_lp };
- let mp = if may_mp == 0 { 51820 } else { may_mp };
-
- let mut state_rw_guard = state.write().await;
- let state_rw = state_rw_guard.deref_mut();
-
- let wg_api = match add_network(
- &mut state_rw.hostfile,
- name.clone(),
- key.to_string(),
- ip_string,
- lp,
- &HashMap::new(),
- )
- .await
- {
- Ok(wg_api) => wg_api,
- Err(e) => {
- warn!("AddNetwork couldn't add network: {e}");
- return ctx.reply(Err(MethodErr::failed(&e)));
- }
- };
-
- // TODO ins wg_api
- let listener = match TcpListener::bind((ip, mp)).await {
- Ok(l) => l,
- Err(e) => {
- let _ = wg_api.remove_interface();
- warn!("AddNetwork couldn't start listener: {e}");
- return ctx.reply(Err(MethodErr::failed(&e)));
- }
- };
- let h = task::spawn(print_error(run_network(
- state.clone(),
- listener,
- name.clone(),
- )));
-
- state_rw.nw_handles.insert(name.clone(), (wg_api, h));
-
- // TODO save new config
-
- ctx.reply(Ok((true,)))
-}
-
-async fn add_network(
- hostfile: &mut Option<(String, BTreeSet<String>)>,
- name: String,
- privkey: String,
- address: String,
- port: u16,
- peers: &HashMap<Key, PeerConfig>,
-) -> Result<WGApi, 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)) = 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();
- }
-
- if let Some((hosts_str, _)) = hostfile {
- debug!("writing hosts file: {hosts_str}");
-
- let mut f = AtomicWriteFile::open("/etc/hosts")?;
- f.write(hosts_str.as_bytes())?;
- f.commit()?;
- }
-
- Ok(wg)
-}
-
-async fn print_error<E: std::fmt::Display, O, F: std::future::Future<Output = Result<O, E>>>(
+pub async fn print_error<E: std::fmt::Display, O, F: std::future::Future<Output = Result<O, E>>>(
f: F,
) -> () {
match f.await {
@@ -411,11 +253,3 @@ async fn print_error<E: std::fmt::Display, O, F: std::future::Future<Output = Re
_ => (),
};
}
-
-async fn run_network(
- state: Arc<RwLock<State>>,
- sock: TcpListener,
- nw_name: String,
-) -> Result<(), DaemonError> {
- Ok(())
-}
diff --git a/src/daemon_dbus.rs b/src/daemon_dbus.rs
new file mode 100644
index 0000000..7065eec
--- /dev/null
+++ b/src/daemon_dbus.rs
@@ -0,0 +1,98 @@
+use base64::prelude::*;
+use dbus::{channel::MatchingReceiver, message::MatchRule};
+use dbus_crossroads::{Context, Crossroads, MethodErr};
+use defguard_wireguard_rs::{
+ host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi,
+};
+use log::{debug, error, info, warn};
+use rand::Rng;
+use std::{
+ collections::{BTreeSet, HashMap},
+ marker::PhantomData,
+ ops::DerefMut,
+ str::FromStr,
+ sync::Arc,
+};
+use tokio::{
+ net::TcpListener,
+ sync::{broadcast, RwLock},
+ task,
+};
+
+use crate::{daemon::*, daemon_network::*};
+
+// TODO also take peers
+pub async fn handle_add_network(
+ mut ctx: Context,
+ state: Arc<RwLock<State>>,
+ (name, may_key, may_ip, may_lp, may_mp): (String, String, String, u16, u16),
+) -> PhantomData<(bool,)> {
+ // 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(),
+ _ => {
+ warn!("AddNetwork with bad key");
+ 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) {
+ Ok(ip_mask) => (ip_mask.ip, may_ip),
+ Err(_) => {
+ warn!("AddNetwork with bad ip");
+ return ctx.reply(Err(MethodErr::invalid_arg("invalid ip")));
+ }
+ },
+ };
+
+ let lp = if may_lp == 0 { 25565 } else { may_lp };
+ let mp = if may_mp == 0 { 51820 } else { may_mp };
+
+ let mut state_rw_guard = state.write().await;
+ let state_rw = state_rw_guard.deref_mut();
+
+ let wg_api = match add_network(
+ &mut state_rw.hostfile,
+ name.clone(),
+ key.to_string(),
+ ip_string,
+ lp,
+ &HashMap::new(),
+ )
+ .await
+ {
+ Ok(wg_api) => wg_api,
+ Err(e) => {
+ warn!("AddNetwork couldn't add network: {e}");
+ return ctx.reply(Err(MethodErr::failed(&e)));
+ }
+ };
+
+ // TODO ins wg_api
+ let listener = match TcpListener::bind((ip, mp)).await {
+ Ok(l) => l,
+ Err(e) => {
+ let _ = wg_api.remove_interface();
+ warn!("AddNetwork couldn't start listener: {e}");
+ return ctx.reply(Err(MethodErr::failed(&e)));
+ }
+ };
+ let h = task::spawn(print_error(run_network(
+ state.clone(),
+ listener,
+ name.clone(),
+ )));
+
+ state_rw.nw_handles.insert(name.clone(), (wg_api, h));
+
+ // TODO save new config
+
+ ctx.reply(Ok((true,)))
+}
diff --git a/src/daemon_network.rs b/src/daemon_network.rs
new file mode 100644
index 0000000..895e409
--- /dev/null
+++ b/src/daemon_network.rs
@@ -0,0 +1,102 @@
+use atomic_write_file::AtomicWriteFile;
+use defguard_wireguard_rs::{
+ host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi,
+};
+use log::{debug, error, info, warn};
+use std::{
+ collections::{BTreeSet, HashMap},
+ io::Write,
+ net::ToSocketAddrs,
+ sync::Arc,
+};
+use tokio::{
+ net::TcpListener,
+ sync::{broadcast, RwLock},
+};
+
+use crate::daemon::*;
+
+pub async fn add_network(
+ hostfile: &mut Option<(String, BTreeSet<String>)>,
+ name: String,
+ privkey: String,
+ address: String,
+ port: u16,
+ peers: &HashMap<Key, PeerConfig>,
+) -> Result<WGApi, 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)) = 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();
+ }
+
+ if let Some((hosts_str, _)) = hostfile {
+ debug!("writing hosts file: {hosts_str}");
+
+ let mut f = AtomicWriteFile::open("/etc/hosts")?;
+ f.write(hosts_str.as_bytes())?;
+ f.commit()?;
+ }
+
+ Ok(wg)
+}
+
+pub async fn run_network(
+ state: Arc<RwLock<State>>,
+ sock: TcpListener,
+ nw_name: String,
+) -> Result<(), DaemonError> {
+ Ok(())
+}
diff --git a/src/main.rs b/src/main.rs
index b7300a7..705b39d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,8 @@
#![feature(if_let_guard)]
pub mod daemon;
+pub mod daemon_dbus;
+pub mod daemon_network;
use clap::{Parser, Subcommand};
use daemon::daemon;