aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2025-03-17 15:58:26 +0100
committerHimbeer <himbeer@disroot.org>2025-03-17 15:58:26 +0100
commit02088cc051786b0eba12e2b8e162e3422aacd0bb (patch)
treeca8f762ca439f4fda44c1d650c23d6e12e257663
parent928cc84d24903871b3bb04eaa2ccb8de1c3c3ee5 (diff)
Create, configure and delete links as configured
-rw-r--r--src/main.rs120
1 files changed, 118 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs
index 4db82e7..39a37a4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,7 +2,9 @@ use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io;
-use std::net::IpAddr;
+use std::net::{IpAddr, SocketAddr};
+
+use wireguard_control::backends::kernel as wg;
const CONFIG_PATH: &str = "/data/wg.peers";
@@ -64,7 +66,7 @@ impl From<std::net::AddrParseError> for ConfigError {
}
impl From<wireguard_control::InvalidKey> for ConfigError {
- fn from(e: wireguard_control::InvalidKey) -> ConfigError {
+ fn from(_: wireguard_control::InvalidKey) -> ConfigError {
ConfigError::InvalidKey
}
}
@@ -84,14 +86,43 @@ impl From<std::num::ParseIntError> for ConfigError {
impl std::error::Error for ConfigError {}
#[derive(Debug)]
+enum SetupError {
+ InvalidInterfaceName(String, wireguard_control::InvalidInterfaceName),
+ Io(io::Error),
+}
+
+impl fmt::Display for SetupError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "set up link:")?;
+
+ match self {
+ Self::InvalidInterfaceName(name, e) => {
+ write!(f, "invalid interface name {}: {}", name, e)
+ }
+ Self::Io(e) => write!(f, "io: {}", e),
+ }
+ }
+}
+
+impl From<io::Error> for SetupError {
+ fn from(e: io::Error) -> SetupError {
+ SetupError::Io(e)
+ }
+}
+
+impl std::error::Error for SetupError {}
+
+#[derive(Debug)]
enum Error {
Config(ConfigError),
+ Setup(SetupError),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Config(e) => e.fmt(f),
+ Self::Setup(e) => e.fmt(f),
}
}
}
@@ -102,6 +133,12 @@ impl From<ConfigError> for Error {
}
}
+impl From<SetupError> for Error {
+ fn from(e: SetupError) -> Error {
+ Error::Setup(e)
+ }
+}
+
impl std::error::Error for Error {}
#[derive(Debug)]
@@ -305,4 +342,83 @@ fn run() -> Result<(), Error> {
};
let mut br = io::BufReader::new(f);
let config = Config::parse(&mut br)?;
+
+ for (name, link_stanza) in config.links {
+ match link_stanza {
+ LinkStanza::Link(link) => {
+ delete(name.clone())?;
+ configure(name, link)?;
+ }
+ LinkStanza::Delete => delete(name)?,
+ };
+ }
+
+ Ok(())
+}
+
+fn configure(name: String, link: Link) -> Result<(), SetupError> {
+ let addresses_pretty = link
+ .addresses
+ .iter()
+ .map(|(addr, cidr)| format!("{}/{}", addr, cidr))
+ .reduce(|acc, net| acc + " " + &net)
+ .unwrap_or_default();
+
+ let allowed_ips_pretty = link
+ .allowed_ips
+ .iter()
+ .map(|net| format!("{}/{}", net.address, net.cidr))
+ .reduce(|acc, net| acc + " " + &net)
+ .unwrap_or_default();
+
+ println!("[info] configure {}", name);
+ println!("[info] endpoint: {}", link.endpoint);
+ println!("[info] private key: (hidden)");
+ println!("[info] public key: {}", link.public_key.to_base64());
+ println!("[info] preshared key: (hidden)");
+ println!("[info] addresses: {}", addresses_pretty);
+ println!("[info] AllowedIPs: {}", allowed_ips_pretty);
+ if link.keepalive_seconds == 0 {
+ println!("[info] keepalive: disabled");
+ } else {
+ println!("[info] keepalive: {}", link.keepalive_seconds);
+ }
+
+ let iface: wireguard_control::InterfaceName = match name.parse() {
+ Ok(name) => name,
+ Err(e) => return Err(SetupError::InvalidInterfaceName(name, e)),
+ };
+
+ let mut peer = wireguard_control::PeerConfigBuilder::new(&link.public_key)
+ .set_endpoint(link.endpoint)
+ .set_preshared_key(link.preshared_key)
+ .replace_allowed_ips()
+ .add_allowed_ips(&link.allowed_ips);
+
+ if link.keepalive_seconds != 0 {
+ peer = peer.set_persistent_keepalive_interval(link.keepalive_seconds);
+ }
+
+ wireguard_control::DeviceUpdate::new()
+ .set_keypair(wireguard_control::KeyPair::from_private(link.private_key))
+ .replace_peers()
+ .randomize_listen_port()
+ .add_peer(peer)
+ .apply(&iface, wireguard_control::Backend::Kernel)?;
+
+ Ok(())
+}
+
+fn delete(name: String) -> Result<(), SetupError> {
+ let iface: wireguard_control::InterfaceName = match name.parse() {
+ Ok(name) => name,
+ Err(e) => return Err(SetupError::InvalidInterfaceName(name, e)),
+ };
+
+ match wg::delete_interface(&iface) {
+ Ok(_) => {}
+ Err(e) => println!("[warn] delete {}: {}", name, e),
+ };
+
+ Ok(())
}