use crate::protocols::dns::DnsResolver; use crate::tunnel::TransportAddr; use hyper::header::{HeaderName, HeaderValue}; use once_cell::sync::Lazy; use parking_lot::RwLock; use std::collections::HashMap; use std::net::IpAddr; use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; use tokio_rustls::rustls::pki_types::{DnsName, ServerName}; use tokio_rustls::TlsConnector; use url::{Host, Url}; #[derive(Clone)] pub struct WsClientConfig { pub remote_addr: TransportAddr, pub socket_so_mark: Option, pub http_upgrade_path_prefix: String, pub http_upgrade_credentials: Option, pub http_headers: HashMap, pub http_headers_file: Option, pub http_header_host: HeaderValue, pub timeout_connect: Duration, pub websocket_ping_frequency: Duration, pub websocket_mask_frame: bool, pub http_proxy: Option, pub dns_resolver: DnsResolver, } impl WsClientConfig { pub const fn websocket_scheme(&self) -> &'static str { match self.remote_addr.tls().is_some() { false => "ws", true => "wss", } } pub fn websocket_host_url(&self) -> String { format!("{}:{}", self.remote_addr.host(), self.remote_addr.port()) } pub fn tls_server_name(&self) -> ServerName<'static> { static INVALID_DNS_NAME: Lazy = Lazy::new(|| DnsName::try_from("dns-name-invalid.com").unwrap()); self.remote_addr .tls() .and_then(|tls| tls.tls_sni_override.as_ref()) .map_or_else( || match &self.remote_addr.host() { Host::Domain(domain) => ServerName::DnsName( DnsName::try_from(domain.clone()).unwrap_or_else(|_| INVALID_DNS_NAME.clone()), ), Host::Ipv4(ip) => ServerName::IpAddress(IpAddr::V4(*ip).into()), Host::Ipv6(ip) => ServerName::IpAddress(IpAddr::V6(*ip).into()), }, |sni_override| ServerName::DnsName(sni_override.clone()), ) } } #[derive(Clone)] pub struct TlsClientConfig { pub tls_sni_disabled: bool, pub tls_sni_override: Option>, pub tls_verify_certificate: bool, pub tls_connector: Arc>, pub tls_certificate_path: Option, pub tls_key_path: Option, } impl TlsClientConfig { pub fn tls_connector(&self) -> TlsConnector { self.tls_connector.read().clone() } }