Compare commits

...

2 Commits

Author SHA1 Message Date
wucke13
c2f8f9006a add control socket serde code 2023-10-19 23:40:08 +02:00
wucke13
c072b7825f add uds control socket to rosenpass
- add new, optional configuration parameter to the config file, `control_socket`
- enhance debug and trace logging in `app_server.rs`
- add optional attribute `maybe_control_socket` to `AppServer`
- registers the uds (if present) in mio, so that one `mio::poll` call can both check on control commands and normal handshake traffic
- sprinkle a little more documentation over `app_server.rs`
- inject control socket handling skeleton code to `AppServer::try_recv`
  - control socket is always processed first, then incoming traffic
2023-09-23 13:21:58 +02:00
6 changed files with 99 additions and 2 deletions

View File

@@ -2,6 +2,7 @@ public_key = "peer-a-public-key"
secret_key = "peer-a-secret-key" secret_key = "peer-a-secret-key"
listen = ["[::]:10001"] listen = ["[::]:10001"]
verbosity = "Quiet" verbosity = "Quiet"
control_socket = "rosenpassd.sock"
[[peers]] [[peers]]
public_key = "peer-b-public-key" public_key = "peer-b-public-key"

View File

@@ -1,6 +1,8 @@
use anyhow::bail; use anyhow::bail;
use anyhow::Result; use anyhow::Result;
use log::debug;
use log::trace;
use log::{error, info, warn}; use log::{error, info, warn};
use mio::Interest; use mio::Interest;
use mio::Token; use mio::Token;
@@ -15,6 +17,7 @@ use std::net::SocketAddr;
use std::net::SocketAddrV4; use std::net::SocketAddrV4;
use std::net::SocketAddrV6; use std::net::SocketAddrV6;
use std::net::ToSocketAddrs; use std::net::ToSocketAddrs;
use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use std::process::Stdio; use std::process::Stdio;
@@ -30,6 +33,7 @@ use crate::{
const IPV4_ANY_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0); const IPV4_ANY_ADDR: Ipv4Addr = Ipv4Addr::new(0, 0, 0, 0);
const IPV6_ANY_ADDR: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); const IPV6_ANY_ADDR: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
const CONTROL_SOCKET_TOKEN: mio::Token = mio::Token(usize::MAX);
fn ipv4_any_binding() -> SocketAddr { fn ipv4_any_binding() -> SocketAddr {
// addr, port // addr, port
@@ -78,6 +82,9 @@ pub struct AppServer {
pub peers: Vec<AppPeer>, pub peers: Vec<AppPeer>,
pub verbosity: Verbosity, pub verbosity: Verbosity,
pub all_sockets_drained: bool, pub all_sockets_drained: bool,
/// Optional control socket to change the configuration of a running rosenpassd
pub maybe_control_socket: Option<mio::net::UnixDatagram>,
} }
/// A socket pointer is an index assigned to a socket; /// A socket pointer is an index assigned to a socket;
@@ -335,11 +342,13 @@ impl HostPathDiscoveryEndpoint {
} }
impl AppServer { impl AppServer {
pub fn new( pub fn new<P: AsRef<Path> + core::fmt::Debug>(
// TODO @wucke13 check if requiring Debug breaks important types that otherwise fulfill AsRef<Path>
sk: SSk, sk: SSk,
pk: SPk, pk: SPk,
addrs: Vec<SocketAddr>, addrs: Vec<SocketAddr>,
verbosity: Verbosity, verbosity: Verbosity,
uds: Option<P>,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
// setup mio // setup mio
let mio_poll = mio::Poll::new()?; let mio_poll = mio::Poll::new()?;
@@ -417,13 +426,31 @@ impl AppServer {
} }
// register all sockets to mio // register all sockets to mio
debug!("registering all UDP sockets to mio");
for (i, socket) in sockets.iter_mut().enumerate() { for (i, socket) in sockets.iter_mut().enumerate() {
trace!("registering {socket:?}");
mio_poll mio_poll
.registry() .registry()
.register(socket, Token(i), Interest::READABLE)?; .register(socket, Token(i), Interest::READABLE)?;
} }
let mut maybe_control_socket = uds
.map(|p| {
debug!("binding control socket {p:?}");
mio::net::UnixDatagram::bind(p)
})
.transpose()?;
if let Some(control_socket) = &mut maybe_control_socket {
debug!("registering control socket to mio");
mio_poll.registry().register(
control_socket,
CONTROL_SOCKET_TOKEN,
Interest::READABLE,
)?;
}
// TODO use mio::net::UnixStream together with std::os::unix::net::UnixStream for Linux // TODO use mio::net::UnixStream together with std::os::unix::net::UnixStream for Linux
debug!("finalizing AppServer creation");
Ok(Self { Ok(Self {
crypt: CryptoServer::new(sk, pk), crypt: CryptoServer::new(sk, pk),
@@ -433,6 +460,7 @@ impl AppServer {
events, events,
mio_poll, mio_poll,
all_sockets_drained: false, all_sockets_drained: false,
maybe_control_socket,
}) })
} }
@@ -638,6 +666,7 @@ impl AppServer {
Ok(()) Ok(())
} }
// Polls the crypto servers state machine for new actions
pub fn poll(&mut self, rx_buf: &mut [u8]) -> anyhow::Result<AppPollResult> { pub fn poll(&mut self, rx_buf: &mut [u8]) -> anyhow::Result<AppPollResult> {
use crate::protocol::PollResult as C; use crate::protocol::PollResult as C;
use AppPollResult as A; use AppPollResult as A;
@@ -654,7 +683,7 @@ impl AppServer {
} }
} }
/// Tries to receive a new message /// Tries to receive a new control socket command or incoming message
/// ///
/// - might wait for an duration up to `timeout` /// - might wait for an duration up to `timeout`
/// - returns immediately if an error occurs /// - returns immediately if an error occurs
@@ -693,6 +722,27 @@ impl AppServer {
self.mio_poll.poll(&mut self.events, Some(timeout))?; self.mio_poll.poll(&mut self.events, Some(timeout))?;
} }
trace!("checking for new command on control socket");
// control socket always has priority
if let Some(control_socket) = &mut self.maybe_control_socket {
let mut buf = [0u8; 16];
match control_socket.recv(&mut buf) {
Ok(size) => {
// TODO handle command
// to send something here, use the following shell snippet:
//
// printf '\x7\' | nc -NuU rosenpassd.sock
log::debug!("buf received {:?}", &buf[0..size]);
}
Err(e) if e.kind() == ErrorKind::WouldBlock => {
trace!("no new commands on control socket")
}
Err(e) => return Err(e.into()),
}
}
// then normal traffic is processed
let mut would_block_count = 0; let mut would_block_count = 0;
for (sock_no, socket) in self.sockets.iter_mut().enumerate() { for (sock_no, socket) in self.sockets.iter_mut().enumerate() {
match socket.recv_from(buf) { match socket.recv_from(buf) {

View File

@@ -228,6 +228,7 @@ impl Cli {
pk, pk,
config.listen, config.listen,
config.verbosity, config.verbosity,
config.control_socket.as_ref(),
)?); )?);
for cfg_peer in config.peers { for cfg_peer in config.peers {

View File

@@ -25,6 +25,8 @@ pub struct Rosenpass {
#[serde(skip)] #[serde(skip)]
pub config_file_path: PathBuf, pub config_file_path: PathBuf,
pub control_socket: Option<PathBuf>,
} }
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -133,6 +135,7 @@ impl Rosenpass {
verbosity: Verbosity::Quiet, verbosity: Verbosity::Quiet,
peers: vec![], peers: vec![],
config_file_path: PathBuf::new(), config_file_path: PathBuf::new(),
control_socket: None,
} }
} }

38
src/control_commands.rs Normal file
View File

@@ -0,0 +1,38 @@
//! Data structures representing the control messages going over the control socket
//!
//! This module uses the same de-/serialization mechanism as [crate::msgs].
//! If you want to interface with `rosenpassd`, this is where you can look up the format
//! of the messages that are accepted.
use crate::{data_lense, msgs::LenseView, RosenpassError};
data_lense! { ControlComand<C> :=
/// [MsgType] of this message
msg_type: 1
}
#[repr(u8)]
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub enum CommandType {
/// Add one peer
AddPeer = 0x10,
/// Remove all peers that match the given public key
RemovePeerPk = 0x11,
/// Remove all peers that match the given address
RemovePeerIp = 0x12,
}
impl TryFrom<u8> for CommandType {
type Error = RosenpassError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
0x10 => CommandType::AddPeer,
0x11 => CommandType::RemovePeerPk,
0x12 => CommandType::RemovePeerIp,
_ => return Err(RosenpassError::InvalidMessageType(value)),
})
}
}

View File

@@ -8,6 +8,7 @@ pub mod labeled_prf;
pub mod app_server; pub mod app_server;
pub mod cli; pub mod cli;
pub mod config; pub mod config;
pub mod control_commands;
pub mod msgs; pub mod msgs;
pub mod pqkem; pub mod pqkem;
pub mod prftree; pub mod prftree;
@@ -26,6 +27,9 @@ pub enum RosenpassError {
}, },
#[error("invalid message type")] #[error("invalid message type")]
InvalidMessageType(u8), InvalidMessageType(u8),
#[error("invalid command type")]
InvalidCommandType(u8),
} }
impl RosenpassError { impl RosenpassError {