// mod leb128; mod num; mod object; mod proto; use std::{ io::{Read, Write}, net::TcpStream, sync::Arc, }; use anyhow::{ensure, 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; use num::Vu64; use crate::num::Vu32; 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 mut uuid = Uuid::new_v4().as_u128().to_le_bytes(); uuid[0] = 0; uuid[1] = 0; uuid[2] = 0; uuid[3] = 0; tls_conn.write_all(&uuid).context("Can't write UUID")?; let uuid = Uuid::from_bytes(uuid); dbg!(uuid); let mut serv_uuid = [0; 16]; tls_conn.read_exact(&mut serv_uuid)?; let serv_uuid = Uuid::from_bytes(serv_uuid); ensure!(serv_uuid != uuid); dbg!(serv_uuid); let mut command_no = 0; let mut recv_buff = Vec::new(); loop { // Recieve step let mut compression = [0]; let l = tls_conn.read(&mut compression)?; match l { 0 => {} 1 => { assert_eq!(compression, [0]); // Handle recieve let len = Vu64::read(&mut tls_conn)?; dbg!(len); recv_buff.resize(len.0 as usize, 0); tls_conn.read_exact(&mut recv_buff)?; dbg!(&recv_buff); let mut recv_buff = &recv_buff[..]; let seq_num = Vu64::read(&mut recv_buff)?; if (seq_num & 1) == 0 { // LSB = 0: This is a call, we need to respond dbg!(seq_num); let command_no = Vu32::read(&mut recv_buff)?; let obj_id = Vu64::read(&mut recv_buff)?; let serialised = recv_buff; dbg!(command_no, obj_id, serialised); } else { // This is a reponce to something we've asked for } } _ => unreachable!("Should only have read one byte"), } } } // 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) // }