From 4a2ecdf123fceb44b5e0e74c48c14930ca1c715e Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Fri, 23 Jun 2023 12:19:14 +0200 Subject: [PATCH] fix: pass IPv6 addresses as host name in TLS connections rustls does not like the brackets `[]` in `rustls::ServerName::try_from()`. Signed-off-by: Harald Hoyer --- src/rtls.rs | 7 +++++++ tests/https-agent.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/rtls.rs b/src/rtls.rs index f83b728..2f149bb 100644 --- a/src/rtls.rs +++ b/src/rtls.rs @@ -115,6 +115,13 @@ impl TlsConnector for Arc { dns_name: &str, mut io: Box, ) -> Result, Error> { + let dns_name = if dns_name.starts_with('[') && dns_name.ends_with(']') { + // rustls doesn't like ipv6 addresses with brackets + &dns_name[1..dns_name.len() - 1] + } else { + dns_name + }; + let sni = rustls::ServerName::try_from(dns_name) .map_err(|e| ErrorKind::Dns.msg(format!("parsing '{}'", dns_name)).src(e))?; diff --git a/tests/https-agent.rs b/tests/https-agent.rs index 0483ad8..b5274cd 100644 --- a/tests/https-agent.rs +++ b/tests/https-agent.rs @@ -150,3 +150,33 @@ m0Wqhhi8/24Sy934t5Txgkfoltg8ahkx934WjP6WWRnSAu+cf+vW assert!(resp.into_string().unwrap().len() > 10); } + +// This tests that IPv6 addresses as host names work. +// This is a regression test for passing the host name to `rustls::ServerName::try_from(host_name)` +#[test] +#[cfg(any(feature = "tls", feature = "tls-native"))] +fn ipv6_addr_in_dns_name() { + let mut root_store = rustls::RootCertStore::empty(); + root_store.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(|ta| { + rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + })); + + let tls_config = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(root_store) + .with_no_client_auth(); + + let agent = ureq::builder() + .tls_config(std::sync::Arc::new(tls_config)) + .build(); + + let resp = agent.get("https://[2606:4700:4700::1111]/").call(); + + assert!( + !matches!(resp, Err(ureq::Error::Transport(ref t)) if t.kind() == ureq::ErrorKind::Dns) + ); +}