use serde::{Deserialize, Serialize};
use std::{net::IpAddr, sync::Arc, time::Duration};
pub const DEFAULT_IDLE_TIMEOUT: Duration = Duration::from_secs(60);
pub const DEFAULT_KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(20);
pub const DEFAULT_UPNP_LEASE_DURATION: Duration = Duration::from_secs(120);
pub const DEFAULT_INITIAL_RETRY_INTERVAL: Duration = Duration::from_millis(500);
pub const DEFAULT_MAX_RETRY_INTERVAL: Duration = Duration::from_secs(15);
pub const DEFAULT_RETRY_INTERVAL_MULTIPLIER: f64 = 1.5;
pub const DEFAULT_RETRY_DELAY_RAND_FACTOR: f64 = 0.3;
pub const DEFAULT_RETRYING_MAX_ELAPSED_TIME: Duration = Duration::from_secs(30);
const MAIDSAFE_DOMAIN: &str = "maidsafe.net";
type Result<T, E = ConfigError> = std::result::Result<T, E>;
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("An error occurred when generating the TLS certificate")]
CertificateGeneration(#[from] CertificateGenerationError),
}
impl From<rcgen::RcgenError> for ConfigError {
fn from(error: rcgen::RcgenError) -> Self {
Self::CertificateGeneration(CertificateGenerationError(error.into()))
}
}
impl From<quinn::ParseError> for ConfigError {
fn from(error: quinn::ParseError) -> Self {
Self::CertificateGeneration(CertificateGenerationError(error.into()))
}
}
impl From<rustls::TLSError> for ConfigError {
fn from(error: rustls::TLSError) -> Self {
Self::CertificateGeneration(CertificateGenerationError(error.into()))
}
}
#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub struct CertificateGenerationError(
Box<dyn std::error::Error + Send + Sync>,
);
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Config {
#[cfg(feature = "igd")]
pub forward_port: bool,
pub external_port: Option<u16>,
pub external_ip: Option<IpAddr>,
#[serde(default)]
pub idle_timeout: Option<Duration>,
#[serde(default)]
pub keep_alive_interval: Option<Duration>,
#[serde(default)]
pub upnp_lease_duration: Option<Duration>,
#[serde(default)]
pub retry_config: RetryConfig,
}
#[derive(Clone, Debug)]
pub(crate) struct InternalConfig {
pub(crate) client: quinn::ClientConfig,
pub(crate) server: quinn::ServerConfig,
#[cfg(feature = "igd")]
pub(crate) forward_port: bool,
pub(crate) external_port: Option<u16>,
pub(crate) external_ip: Option<IpAddr>,
pub(crate) upnp_lease_duration: Duration,
pub(crate) retry_config: RetryConfig,
}
#[derive(Clone, Debug, Copy, Serialize, Deserialize)]
pub struct RetryConfig {
pub initial_retry_interval: Duration,
pub max_retry_interval: Duration,
pub retry_delay_multiplier: f64,
pub retry_delay_rand_factor: f64,
pub retrying_max_elapsed_time: Duration,
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
initial_retry_interval: DEFAULT_INITIAL_RETRY_INTERVAL,
max_retry_interval: DEFAULT_MAX_RETRY_INTERVAL,
retry_delay_multiplier: DEFAULT_RETRY_INTERVAL_MULTIPLIER,
retry_delay_rand_factor: DEFAULT_RETRY_DELAY_RAND_FACTOR,
retrying_max_elapsed_time: DEFAULT_RETRYING_MAX_ELAPSED_TIME,
}
}
}
impl InternalConfig {
pub(crate) fn try_from_config(config: Config) -> Result<Self> {
let idle_timeout = config.idle_timeout.unwrap_or(DEFAULT_IDLE_TIMEOUT);
let keep_alive_interval = config
.keep_alive_interval
.unwrap_or(DEFAULT_KEEP_ALIVE_INTERVAL);
let upnp_lease_duration = config
.upnp_lease_duration
.unwrap_or(DEFAULT_UPNP_LEASE_DURATION);
let transport = Self::new_transport_config(idle_timeout, keep_alive_interval);
let client = Self::new_client_config(transport.clone());
let server = Self::new_server_config(transport)?;
Ok(Self {
client,
server,
#[cfg(feature = "igd")]
forward_port: config.forward_port,
external_port: config.external_port,
external_ip: config.external_ip,
upnp_lease_duration,
retry_config: config.retry_config,
})
}
fn new_transport_config(
idle_timeout: Duration,
keep_alive_interval: Duration,
) -> Arc<quinn::TransportConfig> {
let mut config = quinn::TransportConfig::default();
let _ = config.max_idle_timeout(Some(idle_timeout)).ok();
let _ = config.keep_alive_interval(Some(keep_alive_interval));
Arc::new(config)
}
fn new_client_config(transport: Arc<quinn::TransportConfig>) -> quinn::ClientConfig {
let mut config = quinn::ClientConfig {
transport,
..Default::default()
};
Arc::make_mut(&mut config.crypto)
.dangerous()
.set_certificate_verifier(Arc::new(SkipCertificateVerification));
config
}
fn new_server_config(transport: Arc<quinn::TransportConfig>) -> Result<quinn::ServerConfig> {
let (cert, key) = Self::generate_cert()?;
let mut config = quinn::ServerConfig::default();
config.transport = transport;
let mut config = quinn::ServerConfigBuilder::new(config);
let _ = config.certificate(quinn::CertificateChain::from_certs(vec![cert]), key)?;
Ok(config.build())
}
fn generate_cert() -> Result<(quinn::Certificate, quinn::PrivateKey)> {
let cert = rcgen::generate_simple_self_signed(vec![MAIDSAFE_DOMAIN.to_string()])?;
let cert_der = cert.serialize_der()?;
let key_der = cert.serialize_private_key_der();
Ok((
quinn::Certificate::from_der(&cert_der)?,
quinn::PrivateKey::from_der(&key_der)?,
))
}
}
struct SkipCertificateVerification;
impl rustls::ServerCertVerifier for SkipCertificateVerification {
fn verify_server_cert(
&self,
_roots: &rustls::RootCertStore,
_presented_certs: &[rustls::Certificate],
_dns_name: webpki::DNSNameRef,
_ocsp_response: &[u8],
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
Ok(rustls::ServerCertVerified::assertion())
}
}