mirror of https://github.com/telemt/telemt.git
TLS-F: Fetcher V2
This commit is contained in:
parent
32a9405002
commit
487aa8fbce
|
|
@ -1,19 +1,22 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::time::timeout;
|
use tokio::time::timeout;
|
||||||
use tokio_rustls::client::TlsStream;
|
use tokio_rustls::client::TlsStream;
|
||||||
use tokio_rustls::TlsConnector;
|
use tokio_rustls::TlsConnector;
|
||||||
use tracing::{debug, warn};
|
use tracing::debug;
|
||||||
|
|
||||||
use rustls::client::{ClientConfig, ServerCertVerifier, ServerName};
|
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
|
||||||
|
use rustls::client::ClientConfig;
|
||||||
|
use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
|
||||||
use rustls::{DigitallySignedStruct, Error as RustlsError};
|
use rustls::{DigitallySignedStruct, Error as RustlsError};
|
||||||
use rustls::pki_types::{ServerName as PkiServerName, UnixTime, CertificateDer};
|
|
||||||
|
|
||||||
use crate::tls_front::types::{ParsedServerHello, TlsFetchResult};
|
use crate::tls_front::types::{ParsedServerHello, TlsFetchResult};
|
||||||
|
|
||||||
/// No-op verifier: accept any certificate (we only need lengths and metadata).
|
/// No-op verifier: accept any certificate (we only need lengths and metadata).
|
||||||
|
#[derive(Debug)]
|
||||||
struct NoVerify;
|
struct NoVerify;
|
||||||
|
|
||||||
impl ServerCertVerifier for NoVerify {
|
impl ServerCertVerifier for NoVerify {
|
||||||
|
|
@ -21,11 +24,11 @@ impl ServerCertVerifier for NoVerify {
|
||||||
&self,
|
&self,
|
||||||
_end_entity: &CertificateDer<'_>,
|
_end_entity: &CertificateDer<'_>,
|
||||||
_intermediates: &[CertificateDer<'_>],
|
_intermediates: &[CertificateDer<'_>],
|
||||||
_server_name: &PkiServerName<'_>,
|
_server_name: &ServerName<'_>,
|
||||||
_ocsp: &[u8],
|
_ocsp: &[u8],
|
||||||
_now: UnixTime,
|
_now: UnixTime,
|
||||||
) -> Result<rustls::client::ServerCertVerified, RustlsError> {
|
) -> Result<ServerCertVerified, RustlsError> {
|
||||||
Ok(rustls::client::ServerCertVerified::assertion())
|
Ok(ServerCertVerified::assertion())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_tls12_signature(
|
fn verify_tls12_signature(
|
||||||
|
|
@ -33,8 +36,8 @@ impl ServerCertVerifier for NoVerify {
|
||||||
_message: &[u8],
|
_message: &[u8],
|
||||||
_cert: &CertificateDer<'_>,
|
_cert: &CertificateDer<'_>,
|
||||||
_dss: &DigitallySignedStruct,
|
_dss: &DigitallySignedStruct,
|
||||||
) -> Result<rustls::client::HandshakeSignatureValid, RustlsError> {
|
) -> Result<HandshakeSignatureValid, RustlsError> {
|
||||||
Ok(rustls::client::HandshakeSignatureValid::assertion())
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_tls13_signature(
|
fn verify_tls13_signature(
|
||||||
|
|
@ -42,57 +45,67 @@ impl ServerCertVerifier for NoVerify {
|
||||||
_message: &[u8],
|
_message: &[u8],
|
||||||
_cert: &CertificateDer<'_>,
|
_cert: &CertificateDer<'_>,
|
||||||
_dss: &DigitallySignedStruct,
|
_dss: &DigitallySignedStruct,
|
||||||
) -> Result<rustls::client::HandshakeSignatureValid, RustlsError> {
|
) -> Result<HandshakeSignatureValid, RustlsError> {
|
||||||
Ok(rustls::client::HandshakeSignatureValid::assertion())
|
Ok(HandshakeSignatureValid::assertion())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
|
||||||
|
use rustls::SignatureScheme::*;
|
||||||
|
vec![
|
||||||
|
RSA_PKCS1_SHA256,
|
||||||
|
RSA_PSS_SHA256,
|
||||||
|
ECDSA_NISTP256_SHA256,
|
||||||
|
ECDSA_NISTP384_SHA384,
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_client_config() -> Arc<ClientConfig> {
|
fn build_client_config() -> Arc<ClientConfig> {
|
||||||
let mut root = rustls::RootCertStore::empty();
|
let root = rustls::RootCertStore::empty();
|
||||||
// Optionally load system roots; failure is non-fatal.
|
|
||||||
let _ = root.add_server_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
|
||||||
|
|
||||||
Arc::new(
|
let provider = rustls::crypto::ring::default_provider();
|
||||||
ClientConfig::builder()
|
let mut config = ClientConfig::builder_with_provider(Arc::new(provider))
|
||||||
.with_safe_default_cipher_suites()
|
|
||||||
.with_safe_default_kx_groups()
|
|
||||||
.with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])
|
.with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])
|
||||||
.unwrap()
|
.expect("protocol versions")
|
||||||
.with_custom_certificate_verifier(Arc::new(NoVerify))
|
|
||||||
.with_root_certificates(root)
|
.with_root_certificates(root)
|
||||||
.with_no_client_auth(),
|
.with_no_client_auth();
|
||||||
)
|
|
||||||
|
config
|
||||||
|
.dangerous()
|
||||||
|
.set_certificate_verifier(Arc::new(NoVerify));
|
||||||
|
|
||||||
|
Arc::new(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to fetch real TLS metadata for the given SNI.
|
/// Fetch real TLS metadata for the given SNI: negotiated cipher and cert lengths.
|
||||||
pub async fn fetch_real_tls(
|
pub async fn fetch_real_tls(
|
||||||
host: &str,
|
host: &str,
|
||||||
port: u16,
|
port: u16,
|
||||||
sni: &str,
|
sni: &str,
|
||||||
connect_timeout: Duration,
|
connect_timeout: Duration,
|
||||||
) -> anyhow::Result<TlsFetchResult> {
|
) -> Result<TlsFetchResult> {
|
||||||
let addr = format!("{}:{}", host, port);
|
let addr = format!("{host}:{port}");
|
||||||
let stream = timeout(connect_timeout, TcpStream::connect(addr)).await??;
|
let stream = timeout(connect_timeout, TcpStream::connect(addr)).await??;
|
||||||
|
|
||||||
let config = build_client_config();
|
let config = build_client_config();
|
||||||
let connector = TlsConnector::from(config);
|
let connector = TlsConnector::from(config);
|
||||||
|
|
||||||
let server_name = ServerName::try_from(sni)
|
let server_name = ServerName::try_from(sni.to_owned())
|
||||||
.or_else(|_| ServerName::try_from(host))
|
.or_else(|_| ServerName::try_from(host.to_owned()))
|
||||||
.map_err(|_| RustlsError::General("invalid SNI".into()))?;
|
.map_err(|_| RustlsError::General("invalid SNI".into()))?;
|
||||||
|
|
||||||
let mut tls_stream: TlsStream<TcpStream> = connector.connect(server_name, stream).await?;
|
let tls_stream: TlsStream<TcpStream> = connector.connect(server_name, stream).await?;
|
||||||
|
|
||||||
// Extract negotiated parameters and certificates
|
// Extract negotiated parameters and certificates
|
||||||
let (session, _io) = tls_stream.get_ref();
|
let (_io, session) = tls_stream.get_ref();
|
||||||
let cipher_suite = session
|
let cipher_suite = session
|
||||||
.negotiated_cipher_suite()
|
.negotiated_cipher_suite()
|
||||||
.map(|s| s.suite().get_u16().to_be_bytes())
|
.map(|s| u16::from(s.suite()).to_be_bytes())
|
||||||
.unwrap_or([0x13, 0x01]);
|
.unwrap_or([0x13, 0x01]);
|
||||||
|
|
||||||
let certs: Vec<CertificateDer<'static>> = session
|
let certs: Vec<CertificateDer<'static>> = session
|
||||||
.peer_certificates()
|
.peer_certificates()
|
||||||
.map(|slice| slice.iter().cloned().collect())
|
.map(|slice| slice.to_vec())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let total_cert_len: usize = certs.iter().map(|c| c.len()).sum::<usize>().max(1024);
|
let total_cert_len: usize = certs.iter().map(|c| c.len()).sum::<usize>().max(1024);
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ pub fn resolve_interface_ip(name: &str, want_ipv6: bool) -> Option<IpAddr> {
|
||||||
}
|
}
|
||||||
} else if let Some(v6) = address.as_sockaddr_in6() {
|
} else if let Some(v6) = address.as_sockaddr_in6() {
|
||||||
if want_ipv6 {
|
if want_ipv6 {
|
||||||
return Some(IpAddr::V6(v6.ip().to_std()));
|
return Some(IpAddr::V6(v6.ip().clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -609,7 +609,7 @@ impl UpstreamManager {
|
||||||
}
|
}
|
||||||
let result = tokio::time::timeout(
|
let result = tokio::time::timeout(
|
||||||
Duration::from_secs(DC_PING_TIMEOUT_SECS),
|
Duration::from_secs(DC_PING_TIMEOUT_SECS),
|
||||||
self.ping_single_dc(&upstream_config, addr)
|
self.ping_single_dc(&upstream_config, Some(bind_rr.clone()), addr)
|
||||||
).await;
|
).await;
|
||||||
|
|
||||||
let ping_result = match result {
|
let ping_result = match result {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue