use std::{ io::{Read, Write}, net::TcpStream, sync::Arc, }; use anyhow::{Context, Result}; // use native_tls::TlsConnector; // use native_tls::TlsConnector; use rustls::{ client::{ServerCertVerified, ServerCertVerifier}, ClientConfig, ClientConnection, KeyLogFile, OwnedTrustAnchor, RootCertStore, StreamOwned, }; use trust_dns_resolver::{ config::{ResolverConfig, ResolverOpts}, Resolver, }; use uuid::Uuid; fn main() -> Result<()> { let (port, host) = resolve_dns("daeken.dev")?; let port = 12345; let host = "localhost"; dbg!(&port); dbg!(&host); let tls_conf = Arc::new(make_tls_config()); let mut tls_conn = make_tls_connection(tls_conf, &host, port) .with_context(|| format!("Can't connect to {}:{}", host, port))?; let uuid = Uuid::new_v4(); dbg!(&uuid); tls_conn .write_all(uuid.as_bytes()) .context("Can't write UUID")?; let mut serv_uuid = [0; 16]; tls_conn.read_exact(&mut serv_uuid)?; let serv_uuid = Uuid::from_bytes(serv_uuid); dbg!(serv_uuid); // Hangs ATM let mut new = [0; 100]; tls_conn.write_all(&new)?; let len = tls_conn.read(&mut new)?; dbg!(&new[..len]); Ok(()) } // TODO: How to cache this? fn resolve_dns(server: &str) -> Result<(u16, String)> { let name = format!("_hypercosm._tls.{}", server); let resp = make_dns_client()? .srv_lookup(name)? .into_iter() .collect::>(); // TODO: Ensure exactly 1 result: I think. let srv = &resp[0]; // TODO: Handle priority and weight. let port = srv.port(); // TODO: Should this be ascii or utf8 let name = srv.target().to_ascii(); Ok((port, name)) } fn make_dns_client() -> Result { Ok(Resolver::new( ResolverConfig::cloudflare_tls(), ResolverOpts::default(), )?) } fn make_tls_config() -> ClientConfig { let mut root_store = RootCertStore::empty(); root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) })); // let cert_dir = include_bytes!("../cert.der"); // assert_eq!( // root_store.add_parsable_certificates(&[cert_dir.to_vec()]), // (1, 0) // ); let mut config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); struct DontValidate; impl ServerCertVerifier for DontValidate { fn verify_server_cert( &self, _: &rustls::Certificate, _: &[rustls::Certificate], _: &rustls::ServerName, _: &mut dyn Iterator, _: &[u8], _: std::time::SystemTime, ) -> Result { Ok(ServerCertVerified::assertion()) } } config .dangerous() .set_certificate_verifier(Arc::new(DontValidate)); config.key_log = Arc::new(KeyLogFile::new()); config } fn make_tls_connection( config: Arc, server: &str, port: u16, ) -> Result { let server_name = server .try_into() .with_context(|| format!("Invalid server name: `{}`", server))?; let conn = ClientConnection::new(config, server_name)?; let sock = TcpStream::connect((server, port))?; let stream = StreamOwned::new(conn, sock); Ok(stream) } // fn make_tls_connection( // config: Arc, // server: &str, // port: u16, // ) -> Result { // let connector = TlsConnector::builder() // .danger_accept_invalid_certs(true) // .build()?; // let sock = TcpStream::connect((server, port))?; // let conn = connector.connect(server, sock)?; // Ok(conn) // }