mirror of
https://github.com/rosenpass/rosenpass.git
synced 2025-12-18 13:24:38 +03:00
Compare commits
15 Commits
v0.2.0-rc.
...
dev/add-ud
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2f8f9006a | ||
|
|
c072b7825f | ||
|
|
b7a76849b7 | ||
|
|
d2d72143b5 | ||
|
|
1135cd7bbb | ||
|
|
51f04f749f | ||
|
|
37d1326481 | ||
|
|
d0a84294aa | ||
|
|
a98f64c17d | ||
|
|
d6a7ebe88f | ||
|
|
212336728c | ||
|
|
f48a923dbf | ||
|
|
7b5d0f7d66 | ||
|
|
1e37f89e83 | ||
|
|
b997238f42 |
25
Cargo.lock
generated
25
Cargo.lock
generated
@@ -925,6 +925,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
@@ -1017,7 +1026,7 @@ checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
|
||||
|
||||
[[package]]
|
||||
name = "rosenpass"
|
||||
version = "0.2.0-rc.1"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@@ -1032,6 +1041,7 @@ dependencies = [
|
||||
"oqs-sys",
|
||||
"paste",
|
||||
"serde",
|
||||
"stacker",
|
||||
"static_assertions",
|
||||
"test_bin",
|
||||
"thiserror",
|
||||
@@ -1178,6 +1188,19 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rosenpass"
|
||||
version = "0.2.0-rc.1"
|
||||
version = "0.2.0"
|
||||
authors = ["Karolin Varner <karo@cupdev.net>", "wucke13 <wucke13@gmail.com>"]
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -36,6 +36,7 @@ anyhow = "1.0.71"
|
||||
[dev-dependencies]
|
||||
criterion = "0.4.0"
|
||||
test_bin = "0.4.0"
|
||||
stacker = "0.1.15"
|
||||
|
||||
[features]
|
||||
default = ["log", "env_logger"]
|
||||
|
||||
8
build.rs
8
build.rs
@@ -21,13 +21,13 @@ fn generate_man() -> String {
|
||||
// This function is purposely stupid and redundant
|
||||
|
||||
let man = render_man("mandoc", "./doc/rosenpass.1");
|
||||
if man.is_ok() {
|
||||
return man.unwrap();
|
||||
if let Ok(man) = man {
|
||||
return man;
|
||||
}
|
||||
|
||||
let man = render_man("groff", "./doc/rosenpass.1");
|
||||
if man.is_ok() {
|
||||
return man.unwrap();
|
||||
if let Ok(man) = man {
|
||||
return man;
|
||||
}
|
||||
|
||||
// TODO: Link to online manual here
|
||||
|
||||
@@ -2,6 +2,7 @@ public_key = "peer-a-public-key"
|
||||
secret_key = "peer-a-secret-key"
|
||||
listen = ["[::]:10001"]
|
||||
verbosity = "Quiet"
|
||||
control_socket = "rosenpassd.sock"
|
||||
|
||||
[[peers]]
|
||||
public_key = "peer-b-public-key"
|
||||
|
||||
4
doc/rp.1
4
doc/rp.1
@@ -59,6 +59,10 @@ listening on the provided IP and port combination, allowing connections from
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
In this example, we will assume that the server has an interface bound to
|
||||
192.168.0.1, that accepts incoming connections on port 9999/UDP for Rosenpass
|
||||
and port 10000/UDP for WireGuard.
|
||||
.Pp
|
||||
To create a VPN connection, start by generating secret keys on both hosts.
|
||||
.Bd -literal -offset indent
|
||||
rp genkey server.rosenpass-secret
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use anyhow::bail;
|
||||
|
||||
use anyhow::Result;
|
||||
use log::debug;
|
||||
use log::trace;
|
||||
use log::{error, info, warn};
|
||||
use mio::Interest;
|
||||
use mio::Token;
|
||||
@@ -15,6 +17,7 @@ use std::net::SocketAddr;
|
||||
use std::net::SocketAddrV4;
|
||||
use std::net::SocketAddrV6;
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::process::Stdio;
|
||||
@@ -30,6 +33,7 @@ use crate::{
|
||||
|
||||
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 CONTROL_SOCKET_TOKEN: mio::Token = mio::Token(usize::MAX);
|
||||
|
||||
fn ipv4_any_binding() -> SocketAddr {
|
||||
// addr, port
|
||||
@@ -78,6 +82,9 @@ pub struct AppServer {
|
||||
pub peers: Vec<AppPeer>,
|
||||
pub verbosity: Verbosity,
|
||||
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;
|
||||
@@ -99,7 +106,7 @@ impl SocketPtr {
|
||||
}
|
||||
|
||||
pub fn send_to(&self, srv: &AppServer, buf: &[u8], addr: SocketAddr) -> anyhow::Result<()> {
|
||||
self.get(srv).send_to(&buf, addr)?;
|
||||
self.get(srv).send_to(buf, addr)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -294,13 +301,13 @@ impl HostPathDiscoveryEndpoint {
|
||||
pub fn send_scouting(&self, srv: &AppServer, buf: &[u8]) -> anyhow::Result<()> {
|
||||
let (addr_off, sock_off) = self.scouting_state.get();
|
||||
|
||||
let mut addrs = (&self.addresses)
|
||||
let mut addrs = (self.addresses)
|
||||
.iter()
|
||||
.enumerate()
|
||||
.cycle()
|
||||
.skip(addr_off)
|
||||
.take(self.addresses.len());
|
||||
let mut sockets = (&srv.sockets)
|
||||
let mut sockets = (srv.sockets)
|
||||
.iter()
|
||||
.enumerate()
|
||||
.cycle()
|
||||
@@ -335,11 +342,13 @@ impl HostPathDiscoveryEndpoint {
|
||||
}
|
||||
|
||||
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,
|
||||
pk: SPk,
|
||||
addrs: Vec<SocketAddr>,
|
||||
verbosity: Verbosity,
|
||||
uds: Option<P>,
|
||||
) -> anyhow::Result<Self> {
|
||||
// setup mio
|
||||
let mio_poll = mio::Poll::new()?;
|
||||
@@ -417,13 +426,31 @@ impl AppServer {
|
||||
}
|
||||
|
||||
// register all sockets to mio
|
||||
debug!("registering all UDP sockets to mio");
|
||||
for (i, socket) in sockets.iter_mut().enumerate() {
|
||||
trace!("registering {socket:?}");
|
||||
mio_poll
|
||||
.registry()
|
||||
.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
|
||||
debug!("finalizing AppServer creation");
|
||||
|
||||
Ok(Self {
|
||||
crypt: CryptoServer::new(sk, pk),
|
||||
@@ -433,6 +460,7 @@ impl AppServer {
|
||||
events,
|
||||
mio_poll,
|
||||
all_sockets_drained: false,
|
||||
maybe_control_socket,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -524,9 +552,11 @@ impl AppServer {
|
||||
use AppPollResult::*;
|
||||
use KeyOutputReason::*;
|
||||
match self.poll(&mut *rx)? {
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
SendInitiation(peer) => tx_maybe_with!(peer, || self
|
||||
.crypt
|
||||
.initiate_handshake(peer.lower(), &mut *tx))?,
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
SendRetransmission(peer) => tx_maybe_with!(peer, || self
|
||||
.crypt
|
||||
.retransmit_handshake(peer.lower(), &mut *tx))?,
|
||||
@@ -636,6 +666,7 @@ impl AppServer {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Polls the crypto servers state machine for new actions
|
||||
pub fn poll(&mut self, rx_buf: &mut [u8]) -> anyhow::Result<AppPollResult> {
|
||||
use crate::protocol::PollResult as C;
|
||||
use AppPollResult as A;
|
||||
@@ -652,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`
|
||||
/// - returns immediately if an error occurs
|
||||
@@ -691,6 +722,27 @@ impl AppServer {
|
||||
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;
|
||||
for (sock_no, socket) in self.sockets.iter_mut().enumerate() {
|
||||
match socket.recv_from(buf) {
|
||||
|
||||
13
src/cli.rs
13
src/cli.rs
@@ -164,12 +164,10 @@ impl Cli {
|
||||
// generate the keys and store them in files
|
||||
let mut ssk = crate::protocol::SSk::random();
|
||||
let mut spk = crate::protocol::SPk::random();
|
||||
StaticKEM::keygen(ssk.secret_mut(), spk.secret_mut())?;
|
||||
|
||||
unsafe {
|
||||
StaticKEM::keygen(ssk.secret_mut(), spk.secret_mut())?;
|
||||
ssk.store_secret(skf)?;
|
||||
spk.store_secret(pkf)?;
|
||||
}
|
||||
ssk.store_secret(skf)?;
|
||||
spk.store_secret(pkf)?;
|
||||
}
|
||||
|
||||
ExchangeConfig { config_file } => {
|
||||
@@ -230,6 +228,7 @@ impl Cli {
|
||||
pk,
|
||||
config.listen,
|
||||
config.verbosity,
|
||||
config.control_socket.as_ref(),
|
||||
)?);
|
||||
|
||||
for cfg_peer in config.peers {
|
||||
@@ -252,11 +251,11 @@ impl Cli {
|
||||
}
|
||||
|
||||
trait StoreSecret {
|
||||
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()>;
|
||||
fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
impl<const N: usize> StoreSecret for Secret<N> {
|
||||
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
|
||||
fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
|
||||
std::fs::write(path, self.secret())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ pub struct Rosenpass {
|
||||
|
||||
#[serde(skip)]
|
||||
pub config_file_path: PathBuf,
|
||||
|
||||
pub control_socket: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -133,6 +135,7 @@ impl Rosenpass {
|
||||
verbosity: Verbosity::Quiet,
|
||||
peers: vec![],
|
||||
config_file_path: PathBuf::new(),
|
||||
control_socket: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
38
src/control_commands.rs
Normal file
38
src/control_commands.rs
Normal 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)),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ pub mod labeled_prf;
|
||||
pub mod app_server;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
pub mod control_commands;
|
||||
pub mod msgs;
|
||||
pub mod pqkem;
|
||||
pub mod prftree;
|
||||
@@ -26,6 +27,9 @@ pub enum RosenpassError {
|
||||
},
|
||||
#[error("invalid message type")]
|
||||
InvalidMessageType(u8),
|
||||
|
||||
#[error("invalid command type")]
|
||||
InvalidCommandType(u8),
|
||||
}
|
||||
|
||||
impl RosenpassError {
|
||||
|
||||
@@ -1739,7 +1739,11 @@ mod test {
|
||||
|
||||
// initialize secret and public key for the crypto server
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKEM::keygen(sk.secret_mut(), pk.secret_mut()).expect("unable to generate keys");
|
||||
|
||||
// Guranteed to have 16MB of stack size
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
StaticKEM::keygen(sk.secret_mut(), pk.secret_mut()).expect("unable to generate keys");
|
||||
});
|
||||
|
||||
CryptoServer::new(sk, pk)
|
||||
}
|
||||
|
||||
@@ -172,11 +172,11 @@ trait StoreValue {
|
||||
}
|
||||
|
||||
trait StoreSecret {
|
||||
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()>;
|
||||
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<T: StoreValue> StoreSecret for T {
|
||||
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
self.store(path)
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ impl<const N: usize> LoadValueB64 for Secret<N> {
|
||||
}
|
||||
|
||||
impl<const N: usize> StoreSecret for Secret<N> {
|
||||
unsafe fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
std::fs::write(path, self.secret())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user