use crate::app::{Command, ConnectTarget, SharedState}; use color_eyre::eyre::{bail, Error}; use futures_channel::mpsc::UnboundedReceiver; use mumble_protocol::control::ClientControlCodec; use std::net::ToSocketAddrs; use std::sync::Arc; use tokio::net::TcpStream; use tokio_rustls::rustls; use tokio_rustls::rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; use tokio_rustls::rustls::pki_types::{CertificateDer, ServerName, UnixTime}; use tokio_rustls::rustls::ClientConfig; use tokio_rustls::rustls::DigitallySignedStruct; use tokio_rustls::TlsConnector; use tokio_util::compat::{TokioAsyncReadCompatExt as _, TokioAsyncWriteCompatExt as _}; use tracing::{info, instrument}; use mumble_web2_common::ProxyOverrides; #[derive(Debug)] struct NoCertificateVerification; impl ServerCertVerifier for NoCertificateVerification { fn verify_server_cert( &self, _end_entity: &CertificateDer<'_>, _intermediates: &[CertificateDer<'_>], _server_name: &ServerName<'_>, _ocsp: &[u8], _now: UnixTime, ) -> Result { Ok(rustls::client::danger::ServerCertVerified::assertion()) } fn verify_tls12_signature( &self, _message: &[u8], _cert: &CertificateDer<'_>, _dss: &DigitallySignedStruct, ) -> Result { Ok(HandshakeSignatureValid::assertion()) } fn verify_tls13_signature( &self, _message: &[u8], _cert: &CertificateDer<'_>, _dss: &DigitallySignedStruct, ) -> Result { Ok(HandshakeSignatureValid::assertion()) } fn supported_verify_schemes(&self) -> Vec { vec![ rustls::SignatureScheme::RSA_PKCS1_SHA1, rustls::SignatureScheme::ECDSA_SHA1_Legacy, rustls::SignatureScheme::RSA_PKCS1_SHA256, rustls::SignatureScheme::ECDSA_NISTP256_SHA256, rustls::SignatureScheme::RSA_PKCS1_SHA384, rustls::SignatureScheme::ECDSA_NISTP384_SHA384, rustls::SignatureScheme::RSA_PKCS1_SHA512, rustls::SignatureScheme::ECDSA_NISTP521_SHA512, rustls::SignatureScheme::RSA_PSS_SHA256, rustls::SignatureScheme::RSA_PSS_SHA384, rustls::SignatureScheme::RSA_PSS_SHA512, rustls::SignatureScheme::ED25519, rustls::SignatureScheme::ED448, ] } } #[instrument] pub async fn network_connect( target: ConnectTarget, username: String, event_rx: &mut UnboundedReceiver, overrides: &ProxyOverrides, state: SharedState, ) -> Result<(), Error> { info!("connecting"); let (host, port) = match target { ConnectTarget::Direct { host, port } => (host, port), ConnectTarget::Proxy(_) => { bail!("desktop/mobile platform requires a direct host:port, not a proxy URL") } }; let config = ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(Arc::new(NoCertificateVerification)) .with_no_client_auth(); let connector = TlsConnector::from(Arc::new(config)); let addr = (&*host, port) .to_socket_addrs()? .next() .unwrap(); let server_tcp = TcpStream::connect(addr).await?; let server_stream = connector .connect(host.try_into()?, server_tcp) .await?; let (read_server, write_server) = tokio::io::split(server_stream); let read_codec = ClientControlCodec::new(); let write_codec = ClientControlCodec::new(); let reader = asynchronous_codec::FramedRead::new(read_server.compat(), read_codec); let writer = asynchronous_codec::FramedWrite::new(write_server.compat_write(), write_codec); let (outgoing_send, outgoing_recv) = futures_channel::mpsc::unbounded(); spawn(crate::sender_loop(outgoing_recv, writer)); crate::network_loop(username, state, event_rx, outgoing_send, reader).await } #[allow(unused)] pub use tokio::spawn; #[allow(unused)] pub type SpawnHandle = tokio::runtime::Handle;