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
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
WORKDIR /etc/wireguard
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 log::{info, warn};
@ -9,6 +9,20 @@ use tokio::{
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)]
pub struct StdResult {
pub stdout: String,
@ -31,22 +45,20 @@ pub async fn write_file<P: Into<String>, D: Into<String>>(
data: D,
) -> Result<(), std::io::Error> {
tokio::fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.create(true)
.open(path.into())
.and_then(|mut file| async move {
let result = file.write(data.into().as_bytes()).await;
file.flush().await
})
.and_then(|mut file| async move { file.write(data.into().as_bytes()).await.map(|_| file) })
.and_then(|mut file| async move { file.flush().await })
.await
}
pub async fn read_file<S: Into<String>>(path: S) -> Result<String, std::io::Error> {
tokio::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.write(true)
.read(true)
.open(path.into())
.and_then(|mut file| async move {
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> {
let command = command.into();
pub async fn exec_sh<S: ToString>(command: &S) -> Result<StdResult, Box<dyn Error>> {
let command = command.to_string();
info!("$ {}", command.clone());
let res = match Command::new("sh").arg("-c").arg(command).output().await {
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 stderr_b = &res.stderr.to_vec();
let stdout = match remove_escape(stdout_b) {
Ok(val) => val,
Err(err) => return Err(err.to_string()),
};
let stderr = match remove_escape(stderr_b) {
Ok(val) => val,
Err(err) => return Err(err.to_string()),
};
Ok(StdResult { stdout, stderr })
match remove_escape(stdout_b)
.and_then(|stdout| remove_escape(stderr_b).map(|stderr| (stdout, stderr)))
{
Ok((stdout, stderr)) => Ok(StdResult { stdout, stderr }),
Err(err) => return Err(Box::new(err)),
}
}
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};
@ -6,7 +6,7 @@ use futures_util::TryFutureExt;
use log::error;
use serde::{Deserialize, Serialize};
use tokio::{io::AsyncWriteExt, join};
use tokio::join;
use uuid::Uuid;
use crate::utils::{misc, os};
@ -128,37 +128,45 @@ pub struct 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())
.await
.expect("Could not read memento");
let memento = if memento_str.is_empty() {
if memento_str.is_empty() {
log::info!("Creating new WireGuard configuration...");
let private_key = os::exec_sh("wg genkey").await.expect("error genkey").stdout;
let public_key = os::exec_sh(format!("echo {} | wg pubkey", private_key))
os::exec_sh(&"wg genkey")
.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
.expect("error pubkey")
.stdout;
let address = settings.default_address.clone();
let memento = Memento::new(Server {
private_key,
public_key,
address,
});
log::info!("WireGuard configuration generated...");
memento
.and_then(|(public_key, private_key)| {
let address = settings.default_address.clone();
let memento = Memento::new(Server {
private_key,
public_key,
address,
});
log::info!("WireGuard configuration generated...");
Ok(memento)
})
} else {
serde_json::from_str(&memento_str).expect("Could not serialize memento")
};
Self {
config_path,
memento_path,
memento,
settings,
Ok(serde_json::from_str(&memento_str).expect("Could not serialize memento"))
}
.and_then(|memento| {
Ok(Self {
config_path,
memento_path,
memento,
settings,
})
})
}
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 log::error;
use uuid::Uuid;
use crate::utils::{misc, os};
@ -27,32 +28,46 @@ impl WireGuard {
Self {
name,
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) {
let result = os::exec_sh(format!("wg-quick up {}", &self.name))
os::exec_sh(&format!("wg-quick up {}", &self.name))
.await
.expect("Error");
result.log();
.unwrap_or_else(|err| {
error!("Error quick_up: {}", err);
panic!()
})
.log();
}
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
.expect("Error");
result.log();
.unwrap_or_else(|err| {
error!("Error quick_down: {}", err);
panic!()
})
.log();
}
pub async fn sync_config(&self) {
let result = os::exec_sh(format!(
os::exec_sh(&format!(
"wg syncconf {} <(wg-quick strip {})",
self.name, self.name
))
.await
.expect("Error syncing");
result.log();
.unwrap_or_else(|err| {
error!("Error syncing: {}", err);
panic!()
})
.log();
}
pub async fn start(&mut self) {
@ -64,12 +79,18 @@ impl WireGuard {
}
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 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();
@ -122,29 +143,29 @@ impl WireGuard {
}
pub async fn get_clients(&self) -> Vec<WebClient> {
// let res = os::exec_sh("wg show wg0 dump").await.unwrap();
// let lines: Vec<Vec<String>> = res
// .stdout
// .trim()
// .split('\n')
// .skip(1)
// .map(|line| line.split('\t').map(|x| x.to_string()).collect())
// .collect();
// let lines: Vec<DumpClient> = lines
// .iter()
// .map(|x| DumpClient {
// public_key: x[0].to_string(),
// pre_shared_key: x[1].to_string(),
// endpoint: x[2].to_string(),
// allowed_ips: x[3].to_string(),
// latest_handshake_at: x[4].to_string(),
// transfer_rx: x[5].parse::<i64>().unwrap(),
// transfer_tx: x[6].parse::<i64>().unwrap(),
// persistent_keepalive: x[7].to_string(),
// })
// .collect();
let res = os::exec_sh(&"wg show wg0 dump").await.unwrap();
let lines: Vec<Vec<String>> = res
.stdout
.trim()
.split('\n')
.skip(1)
.map(|line| line.split('\t').map(|x| x.to_string()).collect())
.collect();
let lines: Vec<DumpClient> = lines
.iter()
.map(|x| DumpClient {
public_key: x[0].to_string(),
pre_shared_key: x[1].to_string(),
endpoint: x[2].to_string(),
allowed_ips: x[3].to_string(),
latest_handshake_at: x[4].to_string(),
transfer_rx: x[5].parse::<i64>().unwrap(),
transfer_tx: x[6].parse::<i64>().unwrap(),
persistent_keepalive: x[7].to_string(),
})
.collect();
let memento = self.memento_accessor.get();
let clients: Vec<WebClient> = memento
@ -153,12 +174,12 @@ impl WireGuard {
.map(|(uuid, value)| {
let uuid = uuid.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)) {
// Some(conf) => client_conf = conf,
// None => return None,
// };
match lines.iter().find(|x| x.public_key.eq(&value.public_key)) {
Some(conf) => client_conf = conf,
None => return None,
};
Some(WebClient {
id: uuid,
name: value.name,
@ -167,11 +188,11 @@ impl WireGuard {
public_key: value.public_key,
created_at: value.created_at,
updated_at: value.updated_at,
allowed_ips: "123".to_string(), //client_conf.allowed_ips.to_string(),
persistent_keepalive: "123".to_string(), //client_conf.persistent_keepalive.to_string(),
latest_handshake_at: "123".to_string(), //client_conf.latest_handshake_at.to_string(),
transfer_rx: 1234, //client_conf.transfer_rx,
transfer_tx: 1234, //client_conf.transfer_tx,
allowed_ips: client_conf.allowed_ips.to_string(),
persistent_keepalive: client_conf.persistent_keepalive.to_string(),
latest_handshake_at: client_conf.latest_handshake_at.to_string(),
transfer_rx: client_conf.transfer_rx,
transfer_tx: client_conf.transfer_tx,
})
})
.filter(|x| x.is_some())

Loading…
Cancel
Save