1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//! Allium is a implementation of [onion routing](https://en.wikipedia.org/wiki/Onion_routing)
//! written in Rust. It enables anonymous communication over encrypted tunnels.
//!
//! ## Features
//!
//! - Asynchronous design
//! - Periodic, seamless tunnel reconstruction
//! - Fixed-size packets
//! - Cover traffic
//!
//! ## Getting started
//!
//! Each peer in the onion network requires a RSA keypair to sign its messages.
//! A suitable RSA keypair can be generated with OpenSSL:
//! ```text
//! $ genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out hostkey.pkcs8.pem
//! $ openssl rsa -in hostkey.pkcs8.pem -out hostkey.pem
//! ```
//! Use [`RsaPrivateKey::from_pem_file`] to load the created key.
//!
//! Furthermore, the public keys of other peers in the network must be supplied to verify their identities.
//! A peer can export its public key like this:
//! ```text
//! $ openssl rsa -in hostkey.pem -outform DER -pubout -out hostkey_pub.der
//! ```
//! A remote peer is represented by the [`Peer`] struct which stores the peers address, port and [`RsaPublicKey`].
//!
//! To continuously (re-) build tunnels, the onion router needs a stream of peers which can be used as intermediary nodes in a tunnel.
//! This is requirement is met by the [`PeerProvider`] struct, which can be created from a asynchronous `Stream<Item = Peer>`.
//! The [`PeerProvider`] is fully responsible for the peer sampling.
//!
//! With a [`RsaPrivateKey`] and a [`PeerProvider`] ready, the actual onion router can be constructed.
//! The onion router is split into two parts: a stream of incoming connections and a context
//! allowing the building of new tunnels.
//! Use the [`OnionBuilder`] type to configure the onion router and then call [`OnionBuilder::start`]
//! to obtain a [`OnionIncoming`] stream and a [`OnionContext`].
//!
//! [`OnionContext`] implements [`Clone`], [`Send`] and [`Sync`] allowing to have multiple handles to the
//! same onion router instance.
//! The async method [`OnionContext::build_tunnel`] blocks until a [`Tunnel`] was successfully created and is ready for communication.
//! A [`Tunnel`] can be used similar to a normal socket by calling the [`Tunnel::read`] and [`Tunnel::write`] methods.
//!
//! ## Daemon
//!
//! In addition to being used as a Rust library, Allium can also be run as a stand-alone daemon,
//! which can be controlled over a socket.
//! Refer to the [README](https://github.com/tum-taskforce/allium/blob/master/README.md) for more
//! information on how to use Allium as a daemon.
//!

use std::fmt;
use std::net::SocketAddr;
use tokio::sync::{mpsc, oneshot};
use tokio_stream::{Stream, StreamExt};

mod onion;
mod utils;

pub use crate::onion::crypto::{RsaPrivateKey, RsaPublicKey};
pub use crate::onion::tunnel::TunnelId;
pub use crate::onion::*;

pub type Result<T> = std::result::Result<T, anyhow::Error>;

/// A remote peer characterized by its address, the port on which it is listening for onion
/// connections and its public key.
///
/// The public key is needed to verify the authenticity of signed messages received from this peer.
#[derive(Clone)]
pub struct Peer {
    addr: SocketAddr,
    hostkey: RsaPublicKey,
}

impl Peer {
    pub fn new(addr: SocketAddr, hostkey: RsaPublicKey) -> Self {
        Peer { addr, hostkey }
    }

    pub fn address(&self) -> SocketAddr {
        self.addr
    }
}

impl fmt::Debug for Peer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Peer").field(&self.addr).finish()
    }
}

/// A stream of [`Peer`]s used for constructing tunnels.
///
/// It is up to the user to choose an appropriate peer sampling and caching strategy.
#[derive(Clone)]
pub struct PeerProvider {
    inner: mpsc::Sender<oneshot::Sender<Peer>>,
}

impl PeerProvider {
    /// Turns a given stream of [`Peer`]s into a [`PeerProvider`].
    pub fn from_stream<S>(mut stream: S) -> Self
    where
        S: Stream<Item = Peer> + Unpin + Send + Sync + 'static,
    {
        let (peer_tx, mut peer_rx) = mpsc::channel::<oneshot::Sender<Peer>>(100);
        tokio::spawn(async move {
            while let Some(req) = peer_rx.recv().await {
                let _ = req.send(stream.next().await.unwrap());
            }
        });
        PeerProvider { inner: peer_tx }
    }

    pub(crate) async fn random_peer(&mut self) -> Result<Peer> {
        let (peer_tx, peer_rx) = oneshot::channel();
        let _ = self.inner.send(peer_tx).await;
        Ok(peer_rx.await?)
    }
}