use std::{ io::{Read, Write}, net::TcpStream, str::FromStr, sync::Arc, }; use anyhow::{bail, Context, Result}; use rustls::{ClientConfig, ClientConnection, OwnedTrustAnchor, RootCertStore, StreamOwned}; use trust_dns_resolver::{ config::{ResolverConfig, ResolverOpts}, Resolver, }; use uuid::Uuid; fn main() -> Result<()> { let (port, host) = resolve_dns("daeken.dev")?; 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(); let uuid = [b'a'; 16]; dbg!(&uuid); tls_conn.write_all(&uuid).context("Can't write UUID")?; let mut serv_uuid = [0; 16]; tls_conn.read_exact(&mut serv_uuid)?; dbg!(serv_uuid); 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 config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); config } fn make_tls_connection( config: Arc, server: &str, port: u16, ) -> Result { let server_name = server.try_into()?; let conn = ClientConnection::new(config, server_name)?; let sock = TcpStream::connect((server, port))?; let stream = StreamOwned::new(conn, sock); Ok(stream) }