fn connect(url: &Url) -> rustls::StreamOwned<ClientConnection, TcpStream> {
let host = url.host().expect("");
let sn = server(host);
let stream = {
let cfg = tls_cfg();
let conn = {
let client = ClientConnection::new(cfg, sn).expect("could not connect");
client
};
let addrs = url
.socket_addrs(|| Some(1965))
.expect("could not get addresses for URL");
let addr = addrs.get(0).expect("no addresses");
let sock = TcpStream::connect(addr).expect("failed to connect");
let stream = Stream { conn, sock };
stream
};
stream
}
fn server(host: url::Host<&str>) -> ServerName {
let url::Host::Domain(s) = host
else {unreachable!("the url is always a string")};
let sn = s.try_into().expect("this should be a valid DNS name");
sn
}
fn tls_cfg() -> Arc<rustls::ClientConfig> {
let root_store = rustls::RootCertStore::empty();
let cfg = {
let mut cfg = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth();
cfg.dangerous()
.set_certificate_verifier(Arc::new(danger::Naive {}));
Arc::new(cfg)
};
cfg
}
mod danger {
use std::time::SystemTime;
use rustls::{client::ServerCertVerified, Certificate, Error, ServerName};
// unconditionally trusts
pub struct Naive;
// trust on first use
pub struct Tofu {}
impl rustls::client::ServerCertVerifier for Naive {
fn verify_server_cert(
&self,
_: &Certificate,
_: &[Certificate],
_: &ServerName,
_: &mut dyn Iterator<Item = &[u8]>,
_: &[u8],
_: SystemTime,
) -> Result<ServerCertVerified, Error> {
Ok(ServerCertVerified::assertion())
}
}
}
mod cl {
use clap::Parser;
#[derive(Parser)]
pub struct App {
pub url: Option<String>,
}
}