Browse Source

Refactor config

pull/438/head
Yamzik 4 years ago
parent
commit
c49591f845
  1. 3
      Application.Deploy.Dockerfile
  2. 19
      data/wg0.conf
  3. 20
      data/wg0.json
  4. 50
      src/utils/os.rs
  5. 58
      src/wg_rs/config.rs
  6. 113
      src/wg_rs/wireguard.rs

3
Application.Deploy.Dockerfile

@ -3,7 +3,8 @@ RUN apk add -U --no-cache wireguard-tools dumb-init
FROM alpine_wg AS runtime FROM alpine_wg AS runtime
COPY application/bin/rs-wg /usr/local/cargo/bin/rs-wg COPY application/bin/rs-wg /usr/local/cargo/bin/rs-wg
COPY data/wg /etc/wireguard # COPY data/wireguard /etc/wireguard
CMD [ "mkdir", "/etc/wireguard" ]
COPY data/www /etc/www COPY data/www /etc/www
WORKDIR /etc/wireguard WORKDIR /etc/wireguard
EXPOSE 8080 EXPOSE 8080

19
data/wg0.conf

@ -0,0 +1,19 @@
# Note: Do not edit this file directly.
# Your changes will be overwritten!
# Server
[Interface]
PrivateKey = 7djcxyZBiUQ6OrB36p1cKLGHl1zg5MqQShN9Udl41Hw=
Address = 10.8.0.1/24
ListenPort = 51820
PreUp =
PostUp = iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT;
PreDown =
PostDown =
# Client: 321 (184a9b70-03b3-4bfb-ae89-ce463634f394)
[Peer]
PublicKey = ej10pb+XPRVuotGrkz+423Lku6Jyf5OHqt0ccjx6KU8=
PresharedKey = Y/5LvXKegqRoeugphZZOLS1/Kl+wN+HdJoCdulxzrEs=
AllowedIPs = 10.8.0.2/32

20
data/wg0.json

@ -0,0 +1,20 @@
{
"server": {
"privateKey": "7djcxyZBiUQ6OrB36p1cKLGHl1zg5MqQShN9Udl41Hw=",
"publicKey": "kAW7Jefvgqs5H6hyuF05a1vSZJJdAiedg3AnVdgjFVk=",
"address": "10.8.0.1"
},
"clients": {
"184a9b70-03b3-4bfb-ae89-ce463634f394": {
"uuid": "184a9b70-03b3-4bfb-ae89-ce463634f394",
"name": "321",
"address": "10.8.0.2",
"privateKey": "+K2Bi7AYB1pUCWqIPdRIpqnGFOjG0PE7W8pOBLsatXo=",
"publicKey": "ej10pb+XPRVuotGrkz+423Lku6Jyf5OHqt0ccjx6KU8=",
"preSharedKey": "Y/5LvXKegqRoeugphZZOLS1/Kl+wN+HdJoCdulxzrEs=",
"createdAt": "2022-12-18T15:55:49Z",
"updatedAt": "2022-12-18T15:55:49Z",
"enabled": true
}
}
}

50
src/utils/os.rs

@ -1,4 +1,4 @@
use std::string::FromUtf8Error; use std::{error::Error, string::FromUtf8Error};
use futures_util::TryFutureExt; use futures_util::TryFutureExt;
use log::{info, warn}; use log::{info, warn};
@ -9,6 +9,20 @@ use tokio::{
process::Command, process::Command,
}; };
// pub struct Error<T: ToString> {
// error: T,
// }
// impl<T: ToString> Error<T> {
// pub fn new(error: T) -> Self {
// Self { error }
// }
// }
// impl<T: ToString> ToString for Error<T> {
// fn to_string(&self) -> String {
// self.error.to_string()
// }
// }
#[derive(Serialize)] #[derive(Serialize)]
pub struct StdResult { pub struct StdResult {
pub stdout: String, pub stdout: String,
@ -31,22 +45,20 @@ pub async fn write_file<P: Into<String>, D: Into<String>>(
data: D, data: D,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
tokio::fs::OpenOptions::new() tokio::fs::OpenOptions::new()
.create(true)
.write(true) .write(true)
.truncate(true) .truncate(true)
.create(true)
.open(path.into()) .open(path.into())
.and_then(|mut file| async move { .and_then(|mut file| async move { file.write(data.into().as_bytes()).await.map(|_| file) })
let result = file.write(data.into().as_bytes()).await; .and_then(|mut file| async move { file.flush().await })
file.flush().await
})
.await .await
} }
pub async fn read_file<S: Into<String>>(path: S) -> Result<String, std::io::Error> { pub async fn read_file<S: Into<String>>(path: S) -> Result<String, std::io::Error> {
tokio::fs::OpenOptions::new() tokio::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true) .create(true)
.write(true)
.read(true)
.open(path.into()) .open(path.into())
.and_then(|mut file| async move { .and_then(|mut file| async move {
let mut dst = String::new(); let mut dst = String::new();
@ -84,27 +96,23 @@ pub async fn load_and_read_file_unhandled(path: &str) -> (File, String) {
} }
} }
pub async fn exec_sh<S: Into<String>>(command: S) -> Result<StdResult, String> { pub async fn exec_sh<S: ToString>(command: &S) -> Result<StdResult, Box<dyn Error>> {
let command = command.into(); let command = command.to_string();
info!("$ {}", command.clone()); info!("$ {}", command.clone());
let res = match Command::new("sh").arg("-c").arg(command).output().await { let res = match Command::new("sh").arg("-c").arg(command).output().await {
Ok(val) => val, Ok(val) => val,
Err(err) => return Err(err.to_string()), Err(err) => return Err(Box::new(err)),
}; };
let stdout_b = &res.stdout.to_vec(); let stdout_b = &res.stdout.to_vec();
let stderr_b = &res.stderr.to_vec(); let stderr_b = &res.stderr.to_vec();
let stdout = match remove_escape(stdout_b) { match remove_escape(stdout_b)
Ok(val) => val, .and_then(|stdout| remove_escape(stderr_b).map(|stderr| (stdout, stderr)))
Err(err) => return Err(err.to_string()), {
}; Ok((stdout, stderr)) => Ok(StdResult { stdout, stderr }),
let stderr = match remove_escape(stderr_b) { Err(err) => return Err(Box::new(err)),
Ok(val) => val, }
Err(err) => return Err(err.to_string()),
};
Ok(StdResult { stdout, stderr })
} }
pub fn remove_escape(bytes: &Vec<u8>) -> Result<String, FromUtf8Error> { pub fn remove_escape(bytes: &Vec<u8>) -> Result<String, FromUtf8Error> {

58
src/wg_rs/config.rs

@ -1,4 +1,4 @@
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, error::Error, sync::Arc};
use chrono::{SecondsFormat, SubsecRound, Utc}; use chrono::{SecondsFormat, SubsecRound, Utc};
@ -6,7 +6,7 @@ use futures_util::TryFutureExt;
use log::error; use log::error;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::{io::AsyncWriteExt, join}; use tokio::join;
use uuid::Uuid; use uuid::Uuid;
use crate::utils::{misc, os}; use crate::utils::{misc, os};
@ -128,37 +128,45 @@ pub struct Accessor {
} }
impl Accessor { impl Accessor {
pub async fn new(memento_path: String, config_path: String, settings: Arc<Settings>) -> Self { pub async fn build(
memento_path: String,
config_path: String,
settings: Arc<Settings>,
) -> Result<Self, Box<dyn Error>> {
let memento_str = os::read_file(memento_path.clone()) let memento_str = os::read_file(memento_path.clone())
.await .await
.expect("Could not read memento"); .expect("Could not read memento");
let memento = if memento_str.is_empty() { if memento_str.is_empty() {
log::info!("Creating new WireGuard configuration..."); log::info!("Creating new WireGuard configuration...");
let private_key = os::exec_sh("wg genkey").await.expect("error genkey").stdout; os::exec_sh(&"wg genkey")
let public_key = os::exec_sh(format!("echo {} | wg pubkey", private_key)) .and_then(|res_public| async move {
os::exec_sh(&format!("echo {} | wg pubkey", &res_public.stdout))
.await
.map(|res_private| (res_public.stdout, res_private.stdout))
})
.await .await
.expect("error pubkey") .and_then(|(public_key, private_key)| {
.stdout; let address = settings.default_address.clone();
let memento = Memento::new(Server {
let address = settings.default_address.clone(); private_key,
let memento = Memento::new(Server { public_key,
private_key, address,
public_key, });
address, log::info!("WireGuard configuration generated...");
}); Ok(memento)
log::info!("WireGuard configuration generated..."); })
memento
} else { } else {
serde_json::from_str(&memento_str).expect("Could not serialize memento") Ok(serde_json::from_str(&memento_str).expect("Could not serialize memento"))
};
Self {
config_path,
memento_path,
memento,
settings,
} }
.and_then(|memento| {
Ok(Self {
config_path,
memento_path,
memento,
settings,
})
})
} }
pub async fn set(&mut self, memento: Memento) { pub async fn set(&mut self, memento: Memento) {

113
src/wg_rs/wireguard.rs

@ -2,6 +2,7 @@ use std::sync::Arc;
use chrono::{SecondsFormat, SubsecRound, Utc}; use chrono::{SecondsFormat, SubsecRound, Utc};
use log::error;
use uuid::Uuid; use uuid::Uuid;
use crate::utils::{misc, os}; use crate::utils::{misc, os};
@ -27,32 +28,46 @@ impl WireGuard {
Self { Self {
name, name,
settings: counter.clone(), settings: counter.clone(),
memento_accessor: Accessor::new(memento_path, config_path, counter).await, memento_accessor: Accessor::build(memento_path, config_path, counter)
.await
.unwrap_or_else(|err| {
error!("Error initializing Wireguard: {}", err);
panic!()
}),
} }
} }
pub async fn quick_up(&self) { pub async fn quick_up(&self) {
let result = os::exec_sh(format!("wg-quick up {}", &self.name)) os::exec_sh(&format!("wg-quick up {}", &self.name))
.await .await
.expect("Error"); .unwrap_or_else(|err| {
result.log(); error!("Error quick_up: {}", err);
panic!()
})
.log();
} }
pub async fn quick_down(&self) { pub async fn quick_down(&self) {
let result = os::exec_sh(format!("wg-quick down {}", &self.name)) os::exec_sh(&format!("wg-quick down {}", &self.name))
.await .await
.expect("Error"); .unwrap_or_else(|err| {
result.log(); error!("Error quick_down: {}", err);
panic!()
})
.log();
} }
pub async fn sync_config(&self) { pub async fn sync_config(&self) {
let result = os::exec_sh(format!( os::exec_sh(&format!(
"wg syncconf {} <(wg-quick strip {})", "wg syncconf {} <(wg-quick strip {})",
self.name, self.name self.name, self.name
)) ))
.await .await
.expect("Error syncing"); .unwrap_or_else(|err| {
result.log(); error!("Error syncing: {}", err);
panic!()
})
.log();
} }
pub async fn start(&mut self) { pub async fn start(&mut self) {
@ -64,12 +79,18 @@ impl WireGuard {
} }
pub async fn create_client(&mut self, name: String) -> Client { pub async fn create_client(&mut self, name: String) -> Client {
let private_key = os::exec_sh("wg genkey").await.expect("error genkey").stdout; let private_key = os::exec_sh(&"wg genkey")
.await
.expect("error genkey")
.stdout;
let pub_cmd = format!("echo {} | wg pubkey", private_key); let pub_cmd = format!("echo {} | wg pubkey", private_key);
let public_key = os::exec_sh(pub_cmd).await.expect("error pubkey").stdout; let public_key = os::exec_sh(&pub_cmd).await.expect("error pubkey").stdout;
let pre_shared_key = os::exec_sh("wg genpsk").await.expect("error genpsk").stdout; let pre_shared_key = os::exec_sh(&"wg genpsk")
.await
.expect("error genpsk")
.stdout;
let mut memento = self.memento_accessor.get(); let mut memento = self.memento_accessor.get();
@ -122,29 +143,29 @@ impl WireGuard {
} }
pub async fn get_clients(&self) -> Vec<WebClient> { pub async fn get_clients(&self) -> Vec<WebClient> {
// let res = os::exec_sh("wg show wg0 dump").await.unwrap(); let res = os::exec_sh(&"wg show wg0 dump").await.unwrap();
// let lines: Vec<Vec<String>> = res let lines: Vec<Vec<String>> = res
// .stdout .stdout
// .trim() .trim()
// .split('\n') .split('\n')
// .skip(1) .skip(1)
// .map(|line| line.split('\t').map(|x| x.to_string()).collect()) .map(|line| line.split('\t').map(|x| x.to_string()).collect())
// .collect(); .collect();
// let lines: Vec<DumpClient> = lines let lines: Vec<DumpClient> = lines
// .iter() .iter()
// .map(|x| DumpClient { .map(|x| DumpClient {
// public_key: x[0].to_string(), public_key: x[0].to_string(),
// pre_shared_key: x[1].to_string(), pre_shared_key: x[1].to_string(),
// endpoint: x[2].to_string(), endpoint: x[2].to_string(),
// allowed_ips: x[3].to_string(), allowed_ips: x[3].to_string(),
// latest_handshake_at: x[4].to_string(), latest_handshake_at: x[4].to_string(),
// transfer_rx: x[5].parse::<i64>().unwrap(), transfer_rx: x[5].parse::<i64>().unwrap(),
// transfer_tx: x[6].parse::<i64>().unwrap(), transfer_tx: x[6].parse::<i64>().unwrap(),
// persistent_keepalive: x[7].to_string(), persistent_keepalive: x[7].to_string(),
// }) })
// .collect(); .collect();
let memento = self.memento_accessor.get(); let memento = self.memento_accessor.get();
let clients: Vec<WebClient> = memento let clients: Vec<WebClient> = memento
@ -153,12 +174,12 @@ impl WireGuard {
.map(|(uuid, value)| { .map(|(uuid, value)| {
let uuid = uuid.to_owned(); let uuid = uuid.to_owned();
let value = value.to_owned(); let value = value.to_owned();
// let client_conf; let client_conf;
// match lines.iter().find(|x| x.public_key.eq(&value.public_key)) { match lines.iter().find(|x| x.public_key.eq(&value.public_key)) {
// Some(conf) => client_conf = conf, Some(conf) => client_conf = conf,
// None => return None, None => return None,
// }; };
Some(WebClient { Some(WebClient {
id: uuid, id: uuid,
name: value.name, name: value.name,
@ -167,11 +188,11 @@ impl WireGuard {
public_key: value.public_key, public_key: value.public_key,
created_at: value.created_at, created_at: value.created_at,
updated_at: value.updated_at, updated_at: value.updated_at,
allowed_ips: "123".to_string(), //client_conf.allowed_ips.to_string(), allowed_ips: client_conf.allowed_ips.to_string(),
persistent_keepalive: "123".to_string(), //client_conf.persistent_keepalive.to_string(), persistent_keepalive: client_conf.persistent_keepalive.to_string(),
latest_handshake_at: "123".to_string(), //client_conf.latest_handshake_at.to_string(), latest_handshake_at: client_conf.latest_handshake_at.to_string(),
transfer_rx: 1234, //client_conf.transfer_rx, transfer_rx: client_conf.transfer_rx,
transfer_tx: 1234, //client_conf.transfer_tx, transfer_tx: client_conf.transfer_tx,
}) })
}) })
.filter(|x| x.is_some()) .filter(|x| x.is_some())

Loading…
Cancel
Save