tunneler 0.4.0

Tunnel TCP or UDP traffic over TCP, (mutual) TLS or DNS (authoritative server or direct connection)
Documentation
use std::error::Error;
use std::net::IpAddr;
use std::path::PathBuf;
use std::sync::Arc;

use async_channel::Sender;
use async_trait::async_trait;
use tokio::io::split;
use tokio::net::TcpListener;
use tokio_rustls::rustls::sign::CertifiedKey;
use tokio_rustls::rustls::{
    AllowAnyAuthenticatedClient, ResolvesServerCertUsingSNI, RootCertStore, ServerConfig,
};
use tokio_rustls::TlsAcceptor;

use common::io::Stream;
use common::network::Listener;
use common::tls::{load_certificate, load_signing_key};

use crate::tunnel::{TcpUntunneler, Untunneler};

pub(crate) struct TlsUntunneler {
    untunneler: TcpUntunneler<TlsListener>,
}

impl TlsUntunneler {
    pub(crate) async fn new(
        local_address: IpAddr,
        local_port: u16,
        ca_cert: PathBuf,
        server_cert: PathBuf,
        server_key: PathBuf,
        server_hostname: String,
    ) -> Result<Self, Box<dyn Error>> {
        let mut store = RootCertStore::empty();
        store.add(&load_certificate(ca_cert).await?)?;
        let verifier = AllowAnyAuthenticatedClient::new(store);

        let mut config = ServerConfig::new(verifier);
        let chain = vec![load_certificate(server_cert).await?];
        let mut resolver = ResolvesServerCertUsingSNI::new();
        let signing_key = load_signing_key(server_key).await?;
        resolver.add(
            &server_hostname,
            CertifiedKey::new(chain, Arc::new(signing_key)),
        )?;
        config.cert_resolver = Arc::new(resolver);

        let acceptor = TlsAcceptor::from(Arc::new(config));
        let listener = TlsListener::new(local_address, local_port, acceptor).await?;
        Ok(Self {
            untunneler: TcpUntunneler::from_listener(listener),
        })
    }
}

pub struct TlsListener {
    listener: TcpListener,
    acceptor: TlsAcceptor,
}

impl TlsListener {
    pub async fn new(
        local_address: IpAddr,
        local_port: u16,
        acceptor: TlsAcceptor,
    ) -> Result<Self, Box<dyn Error>> {
        let listener_address = format!("{}:{}", local_address, local_port);
        log::info!("start listening on {}", listener_address);
        let listener = TcpListener::bind(listener_address).await?;
        Ok(Self { listener, acceptor })
    }
}

#[async_trait]
impl Listener for TlsListener {
    async fn accept_clients(&mut self, new_clients: Sender<Stream>) -> Result<(), Box<dyn Error>> {
        while let Ok((client_stream, client_address)) = self.listener.accept().await {
            log::debug!("got connection from {}", client_address);
            let stream = match self.acceptor.accept(client_stream).await {
                Ok(s) => s,
                Err(e) => {
                    log::error!("failed to accept tls from {}: {}", client_address, e);
                    continue;
                }
            };
            let (client_reader, client_writer) = split(stream);
            new_clients
                .send(Stream::new(client_reader, client_writer))
                .await?;
        }
        Ok(())
    }
}

#[async_trait(?Send)]
impl Untunneler for TlsUntunneler {
    async fn untunnel(&mut self, new_clients: Sender<Stream>) -> Result<(), Box<dyn Error>> {
        self.untunneler.untunnel(new_clients).await
    }
}