feat(rosenpass): Add wireguard-broker interface in AppServer (#303)

Dynamically dispatch WireguardBrokerMio trait in AppServer. Also allows for mio event registration and poll processing, logic from dev/broker-architecture branch

Co-authored-by: Prabhpreet Dua <615318+prabhpreet@users.noreply.github.com>
Co-authored-by: Karolin Varner <karo@cupdev.net>
This commit is contained in:
Prabhpreet Dua
2024-05-20 18:12:42 +05:30
committed by GitHub
parent ae7577c641
commit c1abfbfd14
26 changed files with 693 additions and 177 deletions

30
Cargo.lock generated
View File

@@ -427,6 +427,12 @@ dependencies = [
"cc",
]
[[package]]
name = "cobs"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
[[package]]
name = "colorchoice"
version = "1.0.1"
@@ -729,6 +735,12 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "env_logger"
version = "0.10.2"
@@ -954,6 +966,7 @@ dependencies = [
"atomic-polyfill",
"hash32",
"rustc_version",
"serde",
"spin",
"stable_deref_trait",
]
@@ -1515,6 +1528,18 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "postcard"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8"
dependencies = [
"cobs",
"embedded-io",
"heapless",
"serde",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -1667,6 +1692,7 @@ dependencies = [
"rosenpass-secret-memory",
"rosenpass-to",
"rosenpass-util",
"rosenpass-wireguard-broker",
"serde",
"serial_test",
"stacker",
@@ -1772,10 +1798,13 @@ version = "0.1.0"
dependencies = [
"anyhow",
"clap 4.5.4",
"derive_builder 0.20.0",
"env_logger",
"log",
"mio",
"postcard",
"rand",
"rosenpass-secret-memory",
"rosenpass-to",
"rosenpass-util",
"thiserror",
@@ -1802,6 +1831,7 @@ dependencies = [
"rosenpass-ciphers",
"rosenpass-secret-memory",
"rosenpass-util",
"rosenpass-wireguard-broker",
"rtnetlink",
"stacker",
"tempfile",

View File

@@ -34,6 +34,7 @@ rosenpass-ciphers = { path = "ciphers" }
rosenpass-to = { path = "to" }
rosenpass-secret-memory = { path = "secret-memory" }
rosenpass-oqs = { path = "oqs" }
rosenpass-wireguard-broker = { path = "wireguard-broker" }
doc-comment = "0.3.3"
base64ct = {version = "1.6.0", default-features=false}
zeroize = "1.7.0"
@@ -60,6 +61,7 @@ zerocopy = { version = "0.7.34", features = ["derive"] }
home = "0.5.9"
derive_builder = "0.20.0"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
postcard= {version = "1.0.8", features = ["alloc"]}
#Dev dependencies
serial_test = "3.1.1"

View File

@@ -39,6 +39,7 @@ rand = { workspace = true }
zerocopy = { workspace = true }
home = { workspace = true }
derive_builder = {workspace = true}
rosenpass-wireguard-broker = {workspace = true}
[build-dependencies]
anyhow = { workspace = true }
@@ -48,3 +49,6 @@ criterion = { workspace = true }
test_bin = { workspace = true }
stacker = { workspace = true }
serial_test = {workspace = true}
[features]
enable_broker_api = ["rosenpass-wireguard-broker/enable_broker_api"]

View File

@@ -2,13 +2,20 @@ use anyhow::bail;
use anyhow::Result;
use derive_builder::Builder;
use log::{debug, error, info, warn};
use log::{error, info, warn};
use mio::Interest;
use mio::Token;
use rosenpass_util::file::{StoreValueB64, StoreValueB64Writer};
use rosenpass_secret_memory::Public;
use rosenpass_secret_memory::Secret;
use rosenpass_util::file::StoreValueB64;
use rosenpass_wireguard_broker::WireguardBrokerMio;
use rosenpass_wireguard_broker::{WireguardBrokerCfg, WG_KEY_LEN};
use zerocopy::AsBytes;
use std::cell::Cell;
use std::collections::HashMap;
use std::fmt::Debug;
use std::io::ErrorKind;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
@@ -17,10 +24,7 @@ use std::net::SocketAddrV4;
use std::net::SocketAddrV6;
use std::net::ToSocketAddrs;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use std::slice;
use std::thread;
use std::time::Duration;
use std::time::Instant;
@@ -41,6 +45,8 @@ const IPV6_ANY_ADDR: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
const UNDER_LOAD_RATIO: f64 = 0.5;
const DURATION_UPDATE_UNDER_LOAD_STATUS: Duration = Duration::from_millis(500);
const BROKER_ID_BYTES: usize = 8;
fn ipv4_any_binding() -> SocketAddr {
// addr, port
SocketAddr::V4(SocketAddrV4::new(IPV4_ANY_ADDR, 0))
@@ -51,10 +57,50 @@ fn ipv6_any_binding() -> SocketAddr {
SocketAddr::V6(SocketAddrV6::new(IPV6_ANY_ADDR, 0, 0, 0))
}
#[derive(Debug, Default)]
pub struct MioTokenDispenser {
counter: usize,
}
impl MioTokenDispenser {
fn dispense(&mut self) -> Token {
let r = self.counter;
self.counter += 1;
Token(r)
}
}
#[derive(Debug, Default)]
pub struct BrokerStore {
store: HashMap<
Public<BROKER_ID_BYTES>,
Box<dyn WireguardBrokerMio<Error = anyhow::Error, MioError = anyhow::Error>>,
>,
}
#[derive(Debug, Clone)]
pub struct BrokerStorePtr(pub Public<BROKER_ID_BYTES>);
#[derive(Debug)]
pub struct BrokerPeer {
ptr: BrokerStorePtr,
peer_cfg: Box<dyn WireguardBrokerCfg>,
}
impl BrokerPeer {
pub fn new(ptr: BrokerStorePtr, peer_cfg: Box<dyn WireguardBrokerCfg>) -> Self {
Self { ptr, peer_cfg }
}
pub fn ptr(&self) -> &BrokerStorePtr {
&self.ptr
}
}
#[derive(Default, Debug)]
pub struct AppPeer {
pub outfile: Option<PathBuf>,
pub outwg: Option<WireguardOut>, // TODO make this a generic command
pub broker_peer: Option<BrokerPeer>,
pub initial_endpoint: Option<Endpoint>,
pub current_endpoint: Option<Endpoint>,
}
@@ -102,6 +148,8 @@ pub struct AppServer {
pub sockets: Vec<mio::net::UdpSocket>,
pub events: mio::Events,
pub mio_poll: mio::Poll,
pub mio_token_dispenser: MioTokenDispenser,
pub brokers: BrokerStore,
pub peers: Vec<AppPeer>,
pub verbosity: Verbosity,
pub all_sockets_drained: bool,
@@ -159,6 +207,17 @@ impl AppPeerPtr {
pub fn get_app_mut<'a>(&self, srv: &'a mut AppServer) -> &'a mut AppPeer {
&mut srv.peers[self.0]
}
pub fn set_psk(&self, server: &mut AppServer, psk: &Secret<WG_KEY_LEN>) -> anyhow::Result<()> {
if let Some(broker) = server.peers[self.0].broker_peer.as_ref() {
let config = broker.peer_cfg.create_config(psk);
let broker = server.brokers.store.get_mut(&broker.ptr().0).unwrap();
broker.set_psk(config)?;
} else {
log::warn!("No broker peer found for peer {}", self.0);
}
Ok(())
}
}
#[derive(Debug)]
@@ -457,6 +516,7 @@ impl AppServer {
// setup mio
let mio_poll = mio::Poll::new()?;
let events = mio::Events::with_capacity(20);
let mut mio_token_dispenser = MioTokenDispenser::default();
// bind each SocketAddr to a socket
let maybe_sockets: Result<Vec<_>, _> =
@@ -530,10 +590,12 @@ impl AppServer {
}
// register all sockets to mio
for (i, socket) in sockets.iter_mut().enumerate() {
mio_poll
.registry()
.register(socket, Token(i), Interest::READABLE)?;
for socket in sockets.iter_mut() {
mio_poll.registry().register(
socket,
mio_token_dispenser.dispense(),
Interest::READABLE,
)?;
}
// TODO use mio::net::UnixStream together with std::os::unix::net::UnixStream for Linux
@@ -545,6 +607,8 @@ impl AppServer {
sockets,
events,
mio_poll,
mio_token_dispenser,
brokers: BrokerStore::default(),
all_sockets_drained: false,
under_load: DoSOperation::Normal,
blocking_polls_count: 0,
@@ -559,12 +623,50 @@ impl AppServer {
matches!(self.verbosity, Verbosity::Verbose)
}
pub fn register_broker(
&mut self,
broker: Box<dyn WireguardBrokerMio<Error = anyhow::Error, MioError = anyhow::Error>>,
) -> Result<BrokerStorePtr> {
let ptr = Public::from_slice((self.brokers.store.len() as u64).as_bytes());
if self.brokers.store.insert(ptr, broker).is_some() {
bail!("Broker already registered");
}
//Register broker
self.brokers
.store
.get_mut(&ptr)
.ok_or(anyhow::format_err!("Broker wasn't added to registry"))?
.register(
self.mio_poll.registry(),
self.mio_token_dispenser.dispense(),
)?;
Ok(BrokerStorePtr(ptr))
}
pub fn unregister_broker(&mut self, ptr: BrokerStorePtr) -> Result<()> {
//Unregister broker
self.brokers
.store
.get_mut(&ptr.0)
.ok_or_else(|| anyhow::anyhow!("Broker not found"))?
.unregister(self.mio_poll.registry())?;
//Remove broker from store
self.brokers
.store
.remove(&ptr.0)
.ok_or_else(|| anyhow::anyhow!("Broker not found"))?;
Ok(())
}
pub fn add_peer(
&mut self,
psk: Option<SymKey>,
pk: SPk,
outfile: Option<PathBuf>,
outwg: Option<WireguardOut>,
broker_peer: Option<BrokerPeer>,
hostname: Option<String>,
) -> anyhow::Result<AppPeerPtr> {
let PeerPtr(pn) = self.crypt.add_peer(psk, pk)?;
@@ -575,7 +677,7 @@ impl AppServer {
let current_endpoint = None;
self.peers.push(AppPeer {
outfile,
outwg,
broker_peer,
initial_endpoint,
current_endpoint,
});
@@ -735,13 +837,12 @@ impl AppServer {
}
pub fn output_key(
&self,
&mut self,
peer: AppPeerPtr,
why: KeyOutputReason,
key: &SymKey,
) -> anyhow::Result<()> {
let peerid = peer.lower().get(&self.crypt).pidt()?;
let ap = peer.get_app(self);
if self.verbose() {
let msg = match why {
@@ -751,6 +852,8 @@ impl AppServer {
info!("{} {}", msg, peerid.fmt_b64::<MAX_B64_PEER_ID_SIZE>());
}
let ap = peer.get_app(self);
if let Some(of) = ap.outfile.as_ref() {
// This might leave some fragments of the secret on the stack;
// in practice this is likely not a problem because the stack likely
@@ -773,46 +876,7 @@ impl AppServer {
);
}
if let Some(owg) = ap.outwg.as_ref() {
let mut child = match Command::new("wg")
.arg("set")
.arg(&owg.dev)
.arg("peer")
.arg(&owg.pk)
.arg("preshared-key")
.arg("/dev/stdin")
.stdin(Stdio::piped())
.args(&owg.extra_params)
.spawn()
{
Ok(x) => x,
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
anyhow::bail!("Could not find wg command");
} else {
return Err(anyhow::Error::new(e));
}
}
};
if let Err(e) = key.store_b64_writer::<MAX_B64_KEY_SIZE, _>(child.stdin.take().unwrap())
{
error!("could not write psk to wg: {:?}", e);
}
thread::spawn(move || {
let status = child.wait();
if let Ok(status) = status {
if status.success() {
debug!("successfully passed psk to wg")
} else {
error!("could not pass psk to wg {:?}", status)
}
} else {
error!("wait failed: {:?}", status)
}
});
}
peer.set_psk(self, key)?;
Ok(())
}
@@ -944,6 +1008,11 @@ impl AppServer {
// if each socket returned WouldBlock, then we drained them all at least once indeed
self.all_sockets_drained = would_block_count == self.sockets.len();
// Process brokers poll
for (_, broker) in self.brokers.store.iter_mut() {
broker.process_poll()?;
}
Ok(None)
}
}

View File

@@ -4,10 +4,13 @@ use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
use rosenpass_secret_memory::file::StoreSecret;
use rosenpass_util::file::{LoadValue, LoadValueB64};
use rosenpass_wireguard_broker::brokers::native_unix::{
NativeUnixBroker, NativeUnixBrokerConfigBaseBuilder, NativeUnixBrokerConfigBaseBuilderError,
};
use std::path::PathBuf;
use crate::app_server::AppServer;
use crate::app_server::{self, AppServerTest};
use crate::app_server::AppServerTest;
use crate::app_server::{AppServer, BrokerPeer};
use crate::protocol::{SPk, SSk, SymKey};
use super::config;
@@ -314,7 +317,28 @@ impl CliCommand {
test_helpers,
)?);
let broker_store_ptr = srv.register_broker(Box::new(NativeUnixBroker::new()))?;
fn cfg_err_map(e: NativeUnixBrokerConfigBaseBuilderError) -> anyhow::Error {
anyhow::Error::msg(format!("NativeUnixBrokerConfigBaseBuilderError: {:?}", e))
}
for cfg_peer in config.peers {
let broker_peer = if let Some(wg) = &cfg_peer.wg {
let peer_cfg = NativeUnixBrokerConfigBaseBuilder::default()
.peer_id_b64(&wg.peer)?
.interface(wg.device.clone())
.extra_params_ser(&wg.extra_params)?
.build()
.map_err(cfg_err_map)?;
let broker_peer = BrokerPeer::new(broker_store_ptr.clone(), Box::new(peer_cfg));
Some(broker_peer)
} else {
None
};
srv.add_peer(
// psk, pk, outfile, outwg, tx_addr
cfg_peer
@@ -323,11 +347,7 @@ impl CliCommand {
.transpose()?,
SPk::load(&cfg_peer.public_key)?,
cfg_peer.key_out,
cfg_peer.wg.map(|cfg| app_server::WireguardOut {
dev: cfg.device,
pk: cfg.peer,
extra_params: cfg.extra_params,
}),
broker_peer,
cfg_peer.endpoint.clone(),
)?;
}

View File

@@ -135,7 +135,7 @@ impl Rosenpass {
}
// add path to "self"
config.config_file_path = p.as_ref().to_owned();
p.as_ref().clone_into(&mut config.config_file_path);
// return
Ok(config)

View File

@@ -2295,7 +2295,7 @@ mod test {
.secret(),
)
.unwrap()
.mix(&ip_addr_port_a.encode())
.mix(ip_addr_port_a.encode())
.unwrap()
.into_value()[..16]
.to_vec();

View File

@@ -1,7 +1,15 @@
use std::{fs, net::UdpSocket, path::PathBuf, time::Duration};
use std::{
fs,
net::UdpSocket,
path::PathBuf,
sync::{Arc, Mutex},
time::Duration,
};
use clap::Parser;
use clap::{builder::Str, Parser};
use rosenpass::{app_server::AppServerTestBuilder, cli::CliArgs};
use rosenpass_secret_memory::{Public, Secret};
use rosenpass_wireguard_broker::{WireguardBrokerMio, WG_KEY_LEN, WG_PEER_LEN};
use serial_test::serial;
use std::io::Write;
@@ -34,12 +42,7 @@ fn generate_keys() {
}
fn find_udp_socket() -> Option<u16> {
for port in 1025..=u16::MAX {
if UdpSocket::bind(("::1", port)).is_ok() {
return Some(port);
}
}
None
(1025..=u16::MAX).find(|&port| UdpSocket::bind(("::1", port)).is_ok())
}
fn setup_logging() {
@@ -271,3 +274,57 @@ fn check_exchange_under_dos() {
// cleanup
fs::remove_dir_all(&tmpdir).unwrap();
}
#[derive(Debug, Default)]
struct MockBrokerInner {
psk: Option<Secret<WG_KEY_LEN>>,
peer_id: Option<Public<WG_PEER_LEN>>,
interface: Option<String>,
}
#[derive(Debug, Default)]
struct MockBroker {
inner: Arc<Mutex<MockBrokerInner>>,
}
impl WireguardBrokerMio for MockBroker {
type MioError = anyhow::Error;
fn register(
&mut self,
_registry: &mio::Registry,
_token: mio::Token,
) -> Result<(), Self::MioError> {
Ok(())
}
fn process_poll(&mut self) -> Result<(), Self::MioError> {
Ok(())
}
fn unregister(&mut self, _registry: &mio::Registry) -> Result<(), Self::MioError> {
Ok(())
}
}
impl rosenpass_wireguard_broker::WireGuardBroker for MockBroker {
type Error = anyhow::Error;
fn set_psk(
&mut self,
config: rosenpass_wireguard_broker::SerializedBrokerConfig<'_>,
) -> Result<(), Self::Error> {
loop {
let mut lock = self.inner.try_lock();
if let Ok(ref mut mutex) = lock {
**mutex = MockBrokerInner {
psk: Some(config.psk.clone()),
peer_id: Some(config.peer_id.clone()),
interface: Some(std::str::from_utf8(config.interface).unwrap().to_string()),
};
break Ok(());
}
}
}
}

View File

@@ -20,6 +20,7 @@ rosenpass-ciphers = { workspace = true }
rosenpass-cipher-traits = { workspace = true }
rosenpass-secret-memory = { workspace = true }
rosenpass-util = { workspace = true }
rosenpass-wireguard-broker = {workspace = true}
tokio = {workspace = true}

View File

@@ -267,7 +267,7 @@ mod tests {
#[inline]
fn parse(arr: &[&str]) -> Result<Cli, String> {
Cli::parse(arr.into_iter().map(|x| x.to_string()).peekable())
Cli::parse(arr.iter().map(|x| x.to_string()).peekable())
}
#[inline]
@@ -300,7 +300,7 @@ mod tests {
assert!(cli.is_ok());
let cli = cli.unwrap();
assert_eq!(cli.verbose, false);
assert!(!cli.verbose);
assert!(matches!(cli.command, Some(Command::GenKey { .. })));
match cli.command {
@@ -324,7 +324,7 @@ mod tests {
assert!(cli.is_ok());
let cli = cli.unwrap();
assert_eq!(cli.verbose, false);
assert!(!cli.verbose);
assert!(matches!(cli.command, Some(Command::PubKey { .. })));
match cli.command {
@@ -365,7 +365,7 @@ mod tests {
assert!(cli.is_ok());
let cli = cli.unwrap();
assert_eq!(cli.verbose, false);
assert!(!cli.verbose);
assert!(matches!(cli.command, Some(Command::Exchange(_))));
match cli.command {
@@ -391,7 +391,7 @@ mod tests {
assert!(cli.is_ok());
let cli = cli.unwrap();
assert_eq!(cli.verbose, false);
assert!(!cli.verbose);
assert!(matches!(cli.command, Some(Command::Exchange(_))));
match cli.command {
@@ -431,7 +431,7 @@ mod tests {
assert!(cli.is_ok());
let cli = cli.unwrap();
assert_eq!(cli.verbose, false);
assert!(!cli.verbose);
assert!(matches!(cli.command, Some(Command::Exchange(_))));
match cli.command {

View File

@@ -136,12 +136,15 @@ pub async fn exchange(options: ExchangeOptions) -> Result<()> {
use anyhow::anyhow;
use netlink_packet_wireguard::{constants::WG_KEY_LEN, nlas::WgDeviceAttrs};
use rosenpass::{
app_server::{AppServer, WireguardOut},
app_server::{AppServer, BrokerPeer},
config::Verbosity,
protocol::{SPk, SSk, SymKey},
};
use rosenpass_secret_memory::Secret;
use rosenpass_util::file::{LoadValue as _, LoadValueB64};
use rosenpass_wireguard_broker::brokers::native_unix::{
NativeUnixBroker, NativeUnixBrokerConfigBaseBuilder, NativeUnixBrokerConfigBaseBuilderError,
};
let (connection, rtnetlink, _) = rtnetlink::new_connection()?;
tokio::spawn(connection);
@@ -198,6 +201,12 @@ pub async fn exchange(options: ExchangeOptions) -> Result<()> {
None,
)?);
let broker_store_ptr = srv.register_broker(Box::new(NativeUnixBroker::new()))?;
fn cfg_err_map(e: NativeUnixBrokerConfigBaseBuilderError) -> anyhow::Error {
anyhow::Error::msg(format!("NativeUnixBrokerConfigBaseBuilderError: {:?}", e))
}
for peer in options.peers {
let wgpk = peer.public_keys_dir.join("wgpk");
let pqpk = peer.public_keys_dir.join("pqpk");
@@ -220,6 +229,18 @@ pub async fn exchange(options: ExchangeOptions) -> Result<()> {
extra_params.push(allowed_ips.clone());
}
let peer_cfg = NativeUnixBrokerConfigBaseBuilder::default()
.peer_id_b64(&fs::read_to_string(wgpk)?)?
.interface(link_name.clone())
.extra_params_ser(&extra_params)?
.build()
.map_err(cfg_err_map)?;
let broker_peer = Some(BrokerPeer::new(
broker_store_ptr.clone(),
Box::new(peer_cfg),
));
srv.add_peer(
if psk.exists() {
Some(SymKey::load_b64::<WG_B64_LEN, _>(psk))
@@ -229,11 +250,7 @@ pub async fn exchange(options: ExchangeOptions) -> Result<()> {
.transpose()?,
SPk::load(&pqpk)?,
None,
Some(WireguardOut {
dev: link_name.clone(),
pk: fs::read_to_string(wgpk)?,
extra_params,
}),
broker_peer,
peer.endpoint.map(|x| x.to_string()),
)?;
}

View File

@@ -162,12 +162,12 @@ impl<const N: usize> StoreValueB64Writer for Public<N> {
mut writer: W,
) -> Result<(), Self::Error> {
let mut f = [0u8; F];
let encoded_str = b64_encode(&self.value, &mut f)
.with_context(|| format!("Could not encode secret to base64"))?;
let encoded_str =
b64_encode(&self.value, &mut f).with_context(|| "Could not encode secret to base64")?;
writer
.write_all(encoded_str.as_bytes())
.with_context(|| format!("Could not write base64 to writer"))?;
.with_context(|| "Could not write base64 to writer")?;
Ok(())
}
}

View File

@@ -295,11 +295,11 @@ impl<const N: usize> StoreValueB64Writer for Secret<N> {
fn store_b64_writer<const F: usize, W: Write>(&self, mut writer: W) -> anyhow::Result<()> {
let mut f: Secret<F> = Secret::random();
let encoded_str = b64_encode(self.secret(), f.secret_mut())
.with_context(|| format!("Could not encode secret to base64"))?;
.with_context(|| "Could not encode secret to base64")?;
writer
.write_all(encoded_str.as_bytes())
.with_context(|| format!("Could not write base64 to writer"))?;
.with_context(|| "Could not write base64 to writer")?;
f.zeroize();
Ok(())
}

View File

@@ -8,7 +8,7 @@ pub struct B64DisplayHelper<'a, const F: usize>(&'a [u8]);
impl<const F: usize> Display for B64DisplayHelper<'_, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut bytes = [0u8; F];
let string = b64_encode(&self.0, &mut bytes).map_err(|_| std::fmt::Error)?;
let string = b64_encode(self.0, &mut bytes).map_err(|_| std::fmt::Error)?;
let result = f.write_str(string);
bytes.zeroize();
result
@@ -16,17 +16,17 @@ impl<const F: usize> Display for B64DisplayHelper<'_, F> {
}
pub trait B64Display {
fn fmt_b64<'o, const F: usize>(&'o self) -> B64DisplayHelper<'o, F>;
fn fmt_b64<const F: usize>(&self) -> B64DisplayHelper<F>;
}
impl B64Display for [u8] {
fn fmt_b64<'o, const F: usize>(&'o self) -> B64DisplayHelper<'o, F> {
fn fmt_b64<const F: usize>(&self) -> B64DisplayHelper<F> {
B64DisplayHelper(self)
}
}
impl<T: AsRef<[u8]>> B64Display for T {
fn fmt_b64<'o, const F: usize>(&'o self) -> B64DisplayHelper<'o, F> {
fn fmt_b64<const F: usize>(&self) -> B64DisplayHelper<F> {
B64DisplayHelper(self.as_ref())
}
}

View File

@@ -12,6 +12,7 @@ readme = "readme.md"
[dependencies]
thiserror = { workspace = true }
zerocopy = { workspace = true }
rosenpass-secret-memory = {workspace = true}
# Privileged only
wireguard-uapi = { workspace = true }
@@ -23,6 +24,8 @@ anyhow = { workspace = true }
clap = { workspace = true }
env_logger = { workspace = true }
log = { workspace = true }
derive_builder = {workspace = true}
postcard = {workspace = true}
# Mio broker client
mio = { workspace = true }
@@ -32,18 +35,18 @@ rosenpass-util = { workspace = true }
rand = {workspace = true}
[features]
enable_broker=[]
enable_broker_api=[]
[[bin]]
name = "rosenpass-wireguard-broker-privileged"
path = "src/bin/priviledged.rs"
test = false
doc = false
required-features=["enable_broker"]
required-features=["enable_broker_api"]
[[bin]]
name = "rosenpass-wireguard-broker-socket-handler"
test = false
path = "src/bin/socket_handler.rs"
doc = false
required-features=["enable_broker"]
required-features=["enable_broker_api"]

View File

@@ -1,11 +1,17 @@
use std::borrow::BorrowMut;
use std::{borrow::BorrowMut, fmt::Debug};
use crate::{
api::msgs::{self, REQUEST_MSG_BUFFER_SIZE},
WireGuardBroker,
api::{
config::NetworkBrokerConfig,
msgs::{self, REQUEST_MSG_BUFFER_SIZE},
},
SerializedBrokerConfig, WireGuardBroker,
};
use super::msgs::{Envelope, SetPskResponse};
use super::{
config::NetworkBrokerConfigErr,
msgs::{Envelope, SetPskResponse},
};
#[derive(thiserror::Error, Debug, Clone, Eq, PartialEq)]
pub enum BrokerClientPollResponseError<RecvError> {
@@ -34,6 +40,8 @@ fn invalid_msg_poller<RecvError>() -> BrokerClientPollResponseError<RecvError> {
pub enum BrokerClientSetPskError<SendError> {
#[error("Error with encoding/decoding message")]
MsgError,
#[error("Network Broker Config error: {0}")]
BrokerError(NetworkBrokerConfigErr),
#[error(transparent)]
IoError(SendError),
#[error("Interface name out of bounds")]
@@ -51,14 +59,14 @@ pub trait BrokerClientIo {
#[derive(Debug)]
pub struct BrokerClient<Io>
where
Io: BrokerClientIo,
Io: BrokerClientIo + Debug,
{
io: Io,
}
impl<Io> BrokerClient<Io>
where
Io: BrokerClientIo,
Io: BrokerClientIo + Debug,
{
pub fn new(io: Io) -> Self {
Self { io }
@@ -99,16 +107,14 @@ where
impl<Io> WireGuardBroker for BrokerClient<Io>
where
Io: BrokerClientIo,
Io: BrokerClientIo + Debug,
{
type Error = BrokerClientSetPskError<Io::SendError>;
fn set_psk(
&mut self,
iface: &str,
peer_id: [u8; 32],
psk: [u8; 32],
) -> Result<(), Self::Error> {
fn set_psk(&mut self, config: SerializedBrokerConfig) -> Result<(), Self::Error> {
let config: Result<NetworkBrokerConfig, NetworkBrokerConfigErr> = config.try_into();
let config = config.map_err(|e| BrokerClientSetPskError::BrokerError(e))?;
use BrokerClientSetPskError::*;
const BUF_SIZE: usize = REQUEST_MSG_BUFFER_SIZE;
@@ -126,9 +132,10 @@ where
let req = &mut req.payload;
// Populate payload
req.peer_id.copy_from_slice(&peer_id);
req.psk.copy_from_slice(&psk);
req.set_iface(iface).ok_or(IfaceOutOfBounds)?;
req.peer_id.copy_from_slice(&config.peer_id.value);
req.psk.copy_from_slice(config.psk.secret());
req.set_iface(config.iface.as_ref())
.ok_or(IfaceOutOfBounds)?;
}
// Send message

View File

@@ -0,0 +1,43 @@
use crate::{SerializedBrokerConfig, WG_KEY_LEN, WG_PEER_LEN};
use derive_builder::Builder;
use rosenpass_secret_memory::{Public, Secret};
#[derive(Builder)]
#[builder(pattern = "mutable")]
//TODO: Use generics for iface, add additional params
pub struct NetworkBrokerConfig<'a> {
pub iface: &'a str,
pub peer_id: &'a Public<WG_PEER_LEN>,
pub psk: &'a Secret<WG_KEY_LEN>,
}
impl<'a> Into<SerializedBrokerConfig<'a>> for NetworkBrokerConfig<'a> {
fn into(self) -> SerializedBrokerConfig<'a> {
SerializedBrokerConfig {
interface: self.iface.as_bytes(),
peer_id: self.peer_id,
psk: self.psk,
additional_params: &[],
}
}
}
#[derive(thiserror::Error, Debug, Clone, Eq, PartialEq)]
pub enum NetworkBrokerConfigErr {
#[error("Interface")]
Interface,
}
impl<'a> TryFrom<SerializedBrokerConfig<'a>> for NetworkBrokerConfig<'a> {
type Error = NetworkBrokerConfigErr;
fn try_from(value: SerializedBrokerConfig<'a>) -> Result<Self, Self::Error> {
let iface =
std::str::from_utf8(value.interface).map_err(|_| NetworkBrokerConfigErr::Interface)?;
Ok(Self {
iface,
peer_id: value.peer_id,
psk: value.psk,
})
}
}

View File

@@ -1,4 +1,4 @@
pub mod client;
pub mod mio_client;
pub mod config;
pub mod msgs;
pub mod server;

View File

@@ -1,15 +1,21 @@
use std::borrow::BorrowMut;
use std::result::Result;
use rosenpass_secret_memory::{Public, Secret};
use crate::api::msgs::{self, Envelope, SetPskRequest, SetPskResponse};
use crate::WireGuardBroker;
use super::config::{NetworkBrokerConfigBuilder, NetworkBrokerConfigErr};
#[derive(thiserror::Error, Debug, Clone, Eq, PartialEq)]
pub enum BrokerServerError {
#[error("No such request type: {}", .0)]
NoSuchRequestType(u8),
#[error("Invalid message received.")]
InvalidMessage,
#[error("Network Broker Config error: {0}")]
BrokerError(NetworkBrokerConfigErr),
}
impl From<msgs::InvalidMessageTypeError> for BrokerServerError {
@@ -21,16 +27,16 @@ impl From<msgs::InvalidMessageTypeError> for BrokerServerError {
pub struct BrokerServer<Err, Inner>
where
msgs::SetPskError: From<Err>,
Inner: WireGuardBroker<Error = Err>,
msgs::SetPskError: From<Err>,
{
inner: Inner,
}
impl<Err, Inner> BrokerServer<Err, Inner>
where
msgs::SetPskError: From<Err>,
Inner: WireGuardBroker<Error = Err>,
msgs::SetPskError: From<Err>,
{
pub fn new(inner: Inner) -> Self {
Self { inner }
@@ -64,12 +70,20 @@ where
) -> Result<(), BrokerServerError> {
// Using unwrap here since lenses can not return fixed-size arrays
// TODO: Slices should give access to fixed size arrays
let r: Result<(), Err> = self.inner.borrow_mut().set_psk(
req.iface()
.map_err(|_e| BrokerServerError::InvalidMessage)?,
req.peer_id.try_into().unwrap(),
req.psk.try_into().unwrap(),
);
let peer_id = Public::from_slice(&req.peer_id);
let psk = Secret::from_slice(&req.psk);
let interface = req
.iface()
.map_err(|_e| BrokerServerError::InvalidMessage)?;
let config = NetworkBrokerConfigBuilder::default()
.peer_id(&peer_id)
.psk(&psk)
.iface(interface)
.build()
.unwrap();
let r: Result<(), Err> = self.inner.borrow_mut().set_psk(config.into());
let r: msgs::SetPskResult = r.map_err(|e| e.into());
let r: msgs::SetPskResponseReturnCode = r.into();
res.return_code = r as u8;

View File

@@ -3,7 +3,7 @@ use std::result::Result;
use rosenpass_wireguard_broker::api::msgs;
use rosenpass_wireguard_broker::api::server::BrokerServer;
use rosenpass_wireguard_broker::netlink as wg;
use rosenpass_wireguard_broker::brokers::netlink as wg;
#[derive(thiserror::Error, Debug)]
pub enum BrokerAppError {

View File

@@ -1,14 +1,14 @@
use anyhow::{bail, ensure};
use mio::Interest;
use std::collections::VecDeque;
use std::io::{ErrorKind, Read, Write};
use anyhow::{bail, ensure};
use crate::{SerializedBrokerConfig, WireGuardBroker, WireguardBrokerMio};
use crate::WireGuardBroker;
use super::client::{
use crate::api::client::{
BrokerClient, BrokerClientIo, BrokerClientPollResponseError, BrokerClientSetPskError,
};
use super::msgs::{self, RESPONSE_MSG_BUFFER_SIZE};
use crate::api::msgs::{self, RESPONSE_MSG_BUFFER_SIZE};
#[derive(Debug)]
pub struct MioBrokerClient {
@@ -47,7 +47,7 @@ impl MioBrokerClient {
Self { inner }
}
pub fn poll(&mut self) -> anyhow::Result<Option<msgs::SetPskResult>> {
fn poll(&mut self) -> anyhow::Result<Option<msgs::SetPskResult>> {
self.inner.io_mut().flush()?;
// This sucks
@@ -68,18 +68,46 @@ impl MioBrokerClient {
impl WireGuardBroker for MioBrokerClient {
type Error = anyhow::Error;
fn set_psk(&mut self, iface: &str, peer_id: [u8; 32], psk: [u8; 32]) -> anyhow::Result<()> {
fn set_psk<'a>(&mut self, config: SerializedBrokerConfig<'a>) -> anyhow::Result<()> {
use BrokerClientSetPskError::*;
let e = self.inner.set_psk(iface, peer_id, psk);
let e = self.inner.set_psk(config);
match e {
Ok(()) => Ok(()),
Err(IoError(e)) => Err(e),
Err(IfaceOutOfBounds) => bail!("Interface name size is out of bounds."),
Err(MsgError) => bail!("Error with encoding/decoding message."),
Err(BrokerError(e)) => bail!("Broker error: {:?}", e),
}
}
}
impl WireguardBrokerMio for MioBrokerClient {
type MioError = anyhow::Error;
fn register(
&mut self,
registry: &mio::Registry,
token: mio::Token,
) -> Result<(), Self::MioError> {
registry.register(
&mut self.inner.io_mut().socket,
token,
Interest::READABLE | Interest::WRITABLE,
)?;
Ok(())
}
fn process_poll(&mut self) -> Result<(), Self::MioError> {
self.poll()?;
Ok(())
}
fn unregister(&mut self, registry: &mio::Registry) -> Result<(), Self::MioError> {
registry.deregister(&mut self.inner.io_mut().socket)?;
Ok(())
}
}
impl BrokerClientIo for MioBrokerClientIo {
type SendError = anyhow::Error;
type RecvError = anyhow::Error;

View File

@@ -0,0 +1,6 @@
#[cfg(feature = "enable_broker_api")]
pub mod mio_client;
#[cfg(feature = "enable_broker_api")]
pub mod netlink;
pub mod native_unix;

View File

@@ -0,0 +1,177 @@
use std::fmt::Debug;
use std::process::{Command, Stdio};
use std::thread;
use derive_builder::Builder;
use log::{debug, error};
use postcard::{from_bytes, to_allocvec};
use rosenpass_secret_memory::{Public, Secret};
use rosenpass_util::b64::b64_decode;
use rosenpass_util::{b64::B64Display, file::StoreValueB64Writer};
use crate::{SerializedBrokerConfig, WireGuardBroker, WireguardBrokerCfg, WireguardBrokerMio};
use crate::{WG_KEY_LEN, WG_PEER_LEN};
const MAX_B64_KEY_SIZE: usize = WG_KEY_LEN * 5 / 3;
const MAX_B64_PEER_ID_SIZE: usize = WG_PEER_LEN * 5 / 3;
#[derive(Debug)]
pub struct NativeUnixBroker {}
impl Default for NativeUnixBroker {
fn default() -> Self {
Self::new()
}
}
impl NativeUnixBroker {
pub fn new() -> Self {
Self {}
}
}
impl WireGuardBroker for NativeUnixBroker {
type Error = anyhow::Error;
fn set_psk(&mut self, config: SerializedBrokerConfig<'_>) -> Result<(), Self::Error> {
let config: NativeUnixBrokerConfig = config.try_into()?;
let peer_id = format!("{}", config.peer_id.fmt_b64::<MAX_B64_PEER_ID_SIZE>());
let mut child = match Command::new("wg")
.arg("set")
.arg(config.interface)
.arg("peer")
.arg(peer_id)
.arg("preshared-key")
.arg("/dev/stdin")
.stdin(Stdio::piped())
.args(config.extra_params)
.spawn()
{
Ok(x) => x,
Err(e) => {
if e.kind() == std::io::ErrorKind::NotFound {
anyhow::bail!("Could not find wg command");
} else {
return Err(anyhow::Error::new(e));
}
}
};
if let Err(e) = config
.psk
.store_b64_writer::<MAX_B64_KEY_SIZE, _>(child.stdin.take().unwrap())
{
error!("could not write psk to wg: {:?}", e);
}
thread::spawn(move || {
let status = child.wait();
if let Ok(status) = status {
if status.success() {
debug!("successfully passed psk to wg")
} else {
error!("could not pass psk to wg {:?}", status)
}
} else {
error!("wait failed: {:?}", status)
}
});
Ok(())
}
}
impl WireguardBrokerMio for NativeUnixBroker {
type MioError = anyhow::Error;
fn register(
&mut self,
_registry: &mio::Registry,
_token: mio::Token,
) -> Result<(), Self::MioError> {
Ok(())
}
fn process_poll(&mut self) -> Result<(), Self::MioError> {
Ok(())
}
fn unregister(&mut self, _registry: &mio::Registry) -> Result<(), Self::MioError> {
Ok(())
}
}
#[derive(Debug, Builder)]
#[builder(pattern = "mutable")]
pub struct NativeUnixBrokerConfigBase {
pub interface: String,
pub peer_id: Public<WG_PEER_LEN>,
#[builder(private)]
pub extra_params: Vec<u8>,
}
impl NativeUnixBrokerConfigBaseBuilder {
pub fn peer_id_b64(
&mut self,
peer_id: &str,
) -> Result<&mut Self, NativeUnixBrokerConfigBaseBuilderError> {
let mut peer_id_b64 = Public::<WG_PEER_LEN>::zero();
b64_decode(peer_id.as_bytes(), &mut peer_id_b64.value).map_err(|_e| {
NativeUnixBrokerConfigBaseBuilderError::ValidationError(
"Failed to parse peer id b64".to_string(),
)
})?;
Ok(self.peer_id(peer_id_b64))
}
pub fn extra_params_ser(
&mut self,
extra_params: &Vec<String>,
) -> Result<&mut Self, NativeUnixBrokerConfigBuilderError> {
let params = to_allocvec(extra_params).map_err(|_e| {
NativeUnixBrokerConfigBuilderError::ValidationError(
"Failed to parse extra params".to_string(),
)
})?;
Ok(self.extra_params(params))
}
}
impl WireguardBrokerCfg for NativeUnixBrokerConfigBase {
fn create_config<'a>(&'a self, psk: &'a Secret<WG_KEY_LEN>) -> SerializedBrokerConfig<'a> {
SerializedBrokerConfig {
interface: self.interface.as_bytes(),
peer_id: &self.peer_id,
psk,
additional_params: &self.extra_params,
}
}
}
#[derive(Debug, Builder)]
#[builder(pattern = "mutable")]
pub struct NativeUnixBrokerConfig<'a> {
pub interface: &'a str,
pub peer_id: &'a Public<WG_PEER_LEN>,
pub psk: &'a Secret<WG_KEY_LEN>,
pub extra_params: Vec<String>,
}
impl<'a> TryFrom<SerializedBrokerConfig<'a>> for NativeUnixBrokerConfig<'a> {
type Error = anyhow::Error;
fn try_from(value: SerializedBrokerConfig<'a>) -> Result<Self, Self::Error> {
let iface = std::str::from_utf8(value.interface)
.map_err(|_| anyhow::Error::msg("Interface UTF8 decoding error"))?;
let extra_params: Vec<String> =
from_bytes(value.additional_params).map_err(anyhow::Error::new)?;
Ok(Self {
interface: iface,
peer_id: value.peer_id,
psk: value.psk,
extra_params,
})
}
}

View File

@@ -1,7 +1,10 @@
use std::fmt::Debug;
use wireguard_uapi::linux as wg;
use crate::api::config::NetworkBrokerConfig;
use crate::api::msgs;
use crate::WireGuardBroker;
use crate::{SerializedBrokerConfig, WireGuardBroker};
#[derive(thiserror::Error, Debug)]
pub enum ConnectError {
@@ -61,39 +64,45 @@ impl NetlinkWireGuardBroker {
}
}
impl Debug for NetlinkWireGuardBroker {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//TODO: Add useful info in Debug
f.debug_struct("NetlinkWireGuardBroker").finish()
}
}
impl WireGuardBroker for NetlinkWireGuardBroker {
type Error = SetPskError;
fn set_psk(
&mut self,
interface: &str,
peer_id: [u8; 32],
psk: [u8; 32],
) -> Result<(), Self::Error> {
fn set_psk(&mut self, config: SerializedBrokerConfig) -> Result<(), Self::Error> {
let config: NetworkBrokerConfig = config
.try_into()
.map_err(|e| SetPskError::NoSuchInterface)?;
// Ensure that the peer exists by querying the device configuration
// TODO: Use InvalidInterfaceError
let state = self
.sock
.get_device(wg::DeviceInterface::from_name(interface.to_owned()))?;
.get_device(wg::DeviceInterface::from_name(config.iface))?;
if state
.peers
.iter()
.find(|p| &p.public_key == &peer_id)
.find(|p| &p.public_key == &config.peer_id.value)
.is_none()
{
return Err(SetPskError::NoSuchPeer);
}
// Peer update description
let mut set_peer = wireguard_uapi::set::Peer::from_public_key(&peer_id);
let mut set_peer = wireguard_uapi::set::Peer::from_public_key(&config.peer_id);
set_peer
.flags
.push(wireguard_uapi::linux::set::WgPeerF::UpdateOnly);
set_peer.preshared_key = Some(&psk);
set_peer.preshared_key = Some(&config.psk.secret());
// Device update description
let mut set_dev = wireguard_uapi::set::Device::from_ifname(interface.to_owned());
let mut set_dev = wireguard_uapi::set::Device::from_ifname(config.iface);
set_dev.peers.push(set_peer);
self.sock.set_device(set_dev)?;

View File

@@ -1,19 +1,40 @@
#[cfg(feature = "enable_broker")]
use std::result::Result;
use rosenpass_secret_memory::{Public, Secret};
use std::{fmt::Debug, result::Result};
#[cfg(feature = "enable_broker")]
pub trait WireGuardBroker {
pub const WG_KEY_LEN: usize = 32;
pub const WG_PEER_LEN: usize = 32;
pub trait WireGuardBroker: Debug {
type Error;
fn set_psk(
&mut self,
interface: &str,
peer_id: [u8; 32],
psk: [u8; 32],
) -> Result<(), Self::Error>;
fn set_psk(&mut self, config: SerializedBrokerConfig<'_>) -> Result<(), Self::Error>;
}
#[cfg(feature = "enable_broker")]
pub trait WireguardBrokerCfg: Debug {
fn create_config<'a>(&'a self, psk: &'a Secret<WG_KEY_LEN>) -> SerializedBrokerConfig<'a>;
}
#[derive(Debug)]
pub struct SerializedBrokerConfig<'a> {
pub interface: &'a [u8],
pub peer_id: &'a Public<WG_PEER_LEN>,
pub psk: &'a Secret<WG_KEY_LEN>,
pub additional_params: &'a [u8],
}
pub trait WireguardBrokerMio: WireGuardBroker {
type MioError;
/// Register interested events for mio::Registry
fn register(
&mut self,
registry: &mio::Registry,
token: mio::Token,
) -> Result<(), Self::MioError>;
/// Run after a mio::poll operation
fn process_poll(&mut self) -> Result<(), Self::MioError>;
fn unregister(&mut self, registry: &mio::Registry) -> Result<(), Self::MioError>;
}
#[cfg(feature = "enable_broker_api")]
pub mod api;
#[cfg(feature = "enable_broker")]
pub mod netlink;
pub mod brokers;

View File

@@ -1,24 +1,28 @@
#[cfg(feature = "enable_broker")]
#[cfg(feature = "enable_broker_api")]
#[cfg(test)]
mod integration_tests {
use rand::Rng;
use rosenpass_wireguard_broker::api::mio_client::MioBrokerClient;
use rosenpass_secret_memory::{Public, Secret};
use rosenpass_wireguard_broker::api::msgs::{
SetPskError, REQUEST_MSG_BUFFER_SIZE, RESPONSE_MSG_BUFFER_SIZE,
};
use rosenpass_wireguard_broker::api::server::{BrokerServer, BrokerServerError};
use rosenpass_wireguard_broker::WireGuardBroker;
use rosenpass_wireguard_broker::brokers::mio_client::MioBrokerClient;
use rosenpass_wireguard_broker::WG_KEY_LEN;
use rosenpass_wireguard_broker::WG_PEER_LEN;
use rosenpass_wireguard_broker::{SerializedBrokerConfig, WireGuardBroker};
use std::io::Read;
use std::sync::{Arc, Mutex};
#[derive(Default)]
#[derive(Default, Debug)]
struct MockServerBrokerInner {
psk: Option<[u8; 32]>,
peer_id: Option<[u8; 32]>,
psk: Option<Secret<WG_KEY_LEN>>,
peer_id: Option<Public<WG_PEER_LEN>>,
interface: Option<String>,
}
#[derive(Debug)]
struct MockServerBroker {
inner: Arc<Mutex<MockServerBrokerInner>>,
}
@@ -32,20 +36,15 @@ mod integration_tests {
impl WireGuardBroker for MockServerBroker {
type Error = SetPskError;
fn set_psk(
&mut self,
interface: &str,
peer_id: [u8; 32],
psk: [u8; 32],
) -> Result<(), Self::Error> {
fn set_psk(&mut self, config: SerializedBrokerConfig) -> Result<(), Self::Error> {
loop {
let mut lock = self.inner.try_lock();
if let Ok(ref mut mutex) = lock {
**mutex = MockServerBrokerInner {
psk: Some(psk),
peer_id: Some(peer_id),
interface: Some(interface.to_string()),
psk: Some(config.psk.clone()),
peer_id: Some(config.peer_id.clone()),
interface: Some(std::str::from_utf8(config.interface).unwrap().to_string()),
};
break;
}
@@ -91,25 +90,34 @@ mod integration_tests {
for _ in 0..TEST_RUNS {
//Create psk of random 32 bytes
let mut psk: [u8; 32] = [0; 32];
rand::thread_rng().fill(&mut psk);
let mut peer_id: [u8; 32] = [0; 32];
rand::thread_rng().fill(&mut peer_id);
let psk = Secret::random();
let peer_id = Public::random();
let interface = "test";
client.set_psk(&interface, peer_id, psk).unwrap();
let config = SerializedBrokerConfig {
psk: &psk,
peer_id: &peer_id,
interface: interface.as_bytes(),
additional_params: &[],
};
client.set_psk(config).unwrap();
//Sleep for a while to allow the server to process the message
std::thread::sleep(std::time::Duration::from_millis(
rand::thread_rng().gen_range(100..500),
));
let psk = psk.secret().to_owned();
loop {
let mut lock = server_broker_inner.try_lock();
if let Ok(ref mut inner) = lock {
// Check if the psk is received by the server
let received_psk = inner.psk;
assert_eq!(received_psk, Some(psk));
let received_psk = &inner.psk;
assert_eq!(
received_psk.as_ref().map(|psk| psk.secret().to_owned()),
Some(psk)
);
let recieved_peer_id = inner.peer_id;
assert_eq!(recieved_peer_id, Some(peer_id));