use crate::{Request, Response, Result, DnsError};
use super::{Transport, TlsConfig};
use super::udp::UdpTransport;
use async_trait::async_trait;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::time::timeout;
use std::sync::{Arc, Mutex};
use crate::{dns_debug, dns_info, dns_error, dns_transport};
use tokio_rustls::{TlsConnector, rustls::{ClientConfig, ServerName}};
pub struct TlsTransport {
#[allow(dead_code)]
connector: Arc<TlsConnector>,
config: Arc<Mutex<TlsConfig>>,
}
impl std::fmt::Debug for TlsTransport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TlsTransport")
.field("config", &self.config)
.finish()
}
}
impl TlsTransport {
pub fn new(config: TlsConfig) -> Result<Self> {
let mut client_config = ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(Self::load_root_certs()?)
.with_no_client_auth();
if !config.verify_cert {
client_config.dangerous()
.set_certificate_verifier(Arc::new(NoVerifier));
}
let connector = TlsConnector::from(Arc::new(client_config));
Ok(Self {
config: Arc::new(Mutex::new(config)),
connector: Arc::new(connector),
})
}
fn load_root_certs() -> Result<tokio_rustls::rustls::RootCertStore> {
let mut root_store = tokio_rustls::rustls::RootCertStore::empty();
match rustls_native_certs::load_native_certs() {
Ok(certs) => {
for cert in certs {
if let Err(e) = root_store.add(&tokio_rustls::rustls::Certificate(cert.0)) {
dns_error!("Failed to add certificate: {:?}", e);
}
}
}
Err(e) => {
return Err(DnsError::Tls(format!("Failed to load native certs: {}", e)));
}
}
if root_store.is_empty() {
root_store.add_server_trust_anchors(
webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| {
tokio_rustls::rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
})
);
}
Ok(root_store)
}
async fn read_tls_response(
stream: &mut tokio_rustls::client::TlsStream<TcpStream>
) -> Result<Vec<u8>> {
let mut length_buf = [0u8; 2];
stream.read_exact(&mut length_buf).await
.map_err(|e| DnsError::Network(format!("Failed to read length: {}", e)))?;
let length = u16::from_be_bytes(length_buf) as usize;
if length == 0 {
return Err(DnsError::Protocol("Invalid response length".to_string()));
}
if length > 65535 {
return Err(DnsError::Protocol("Response too large".to_string()));
}
let mut response_buf = vec![0u8; length];
stream.read_exact(&mut response_buf).await
.map_err(|e| DnsError::Network(format!("Failed to read response: {}", e)))?;
Ok(response_buf)
}
fn serialize_request_tls(request: &Request) -> Result<Vec<u8>> {
let udp_data = UdpTransport::serialize_request(request)?;
let mut tls_data = Vec::with_capacity(udp_data.len() + 2);
tls_data.extend_from_slice(&(udp_data.len() as u16).to_be_bytes());
tls_data.extend_from_slice(&udp_data);
Ok(tls_data)
}
}
#[async_trait]
impl Transport for TlsTransport {
async fn send(&self, request: &Request) -> Result<Response> {
use crate::{dns_debug, dns_info};
let (server_addr, timeout_duration, server_name) = {
let config = self.config.lock().unwrap();
dns_info!("🔒 DoT请求开始: {} -> {}:{}", request.query.name, config.base.server, config.base.port);
(
format!("{}:{}", config.base.server, config.base.port),
config.base.timeout,
config.server_name.clone()
)
};
let connect_result = timeout(
timeout_duration,
TcpStream::connect(&server_addr)
).await;
let tcp_stream = match connect_result {
Ok(Ok(stream)) => stream,
Ok(Err(e)) => return Err(DnsError::Network(format!("Connection failed: {}", e))),
Err(_) => return Err(DnsError::Timeout),
};
let server_name = ServerName::try_from(server_name.as_str())
.map_err(|e| DnsError::Tls(format!("Invalid server name: {}", e)))?;
let tls_result = timeout(
timeout_duration,
self.connector.connect(server_name, tcp_stream)
).await;
let mut tls_stream = match tls_result {
Ok(Ok(stream)) => stream,
Ok(Err(e)) => return Err(DnsError::Tls(format!("TLS handshake failed: {}", e))),
Err(_) => return Err(DnsError::Timeout),
};
let request_data = Self::serialize_request_tls(request)?;
let send_result = timeout(
timeout_duration,
tls_stream.write_all(&request_data)
).await;
match send_result {
Ok(Ok(_)) => {},
Ok(Err(e)) => return Err(DnsError::Network(format!("Send failed: {}", e))),
Err(_) => return Err(DnsError::Timeout),
}
let flush_result = timeout(
timeout_duration,
tls_stream.flush()
).await;
match flush_result {
Ok(Ok(_)) => {},
Ok(Err(e)) => return Err(DnsError::Network(format!("Flush failed: {}", e))),
Err(_) => return Err(DnsError::Timeout),
}
let response_data = timeout(
timeout_duration,
Self::read_tls_response(&mut tls_stream)
).await;
let response_bytes = match response_data {
Ok(Ok(data)) => data,
Ok(Err(e)) => return Err(e),
Err(_) => return Err(DnsError::Timeout),
};
UdpTransport::deserialize_response(&response_bytes)
}
fn transport_type(&self) -> &'static str {
"TLS"
}
fn set_timeout(&mut self, timeout: Duration) {
if let Ok(mut config) = self.config.lock() {
config.base.timeout = timeout;
}
}
fn timeout(&self) -> Duration {
self.config.lock().unwrap().base.timeout
}
}
struct NoVerifier;
impl tokio_rustls::rustls::client::ServerCertVerifier for NoVerifier {
fn verify_server_cert(
&self,
_end_entity: &tokio_rustls::rustls::Certificate,
_intermediates: &[tokio_rustls::rustls::Certificate],
_server_name: &tokio_rustls::rustls::ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8],
_now: std::time::SystemTime,
) -> std::result::Result<tokio_rustls::rustls::client::ServerCertVerified, tokio_rustls::rustls::Error> {
Ok(tokio_rustls::rustls::client::ServerCertVerified::assertion())
}
}