From e681e430707d5b93c08af46168d9ea6fb913703f Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 20 Sep 2019 10:39:42 +0200 Subject: [PATCH] ADd a key cache and improve logging --- encrypted-dns.toml | 5 +++++ src/config.rs | 15 +++++++++++---- src/dnscrypt.rs | 27 +++++++++++++++++++++++++-- src/dnscrypt_certs.rs | 25 ++++++++++++++++++++++--- src/globals.rs | 1 + src/main.rs | 20 ++++++++++++++------ 6 files changed, 78 insertions(+), 15 deletions(-) diff --git a/encrypted-dns.toml b/encrypted-dns.toml index 7a3023d..5d693dd 100644 --- a/encrypted-dns.toml +++ b/encrypted-dns.toml @@ -77,6 +77,11 @@ tcp_max_active_connections = 100 provider_name = "secure.dns.test" +## Key cache capacity, per certificate + +key_cache_capacity = 10000 + + ############################### # TLS settings # diff --git a/src/config.rs b/src/config.rs index 02c4466..ad0d83f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,7 @@ use tokio::prelude::*; #[derive(Serialize, Deserialize, Debug)] pub struct DNSCryptConfig { pub provider_name: String, + pub key_cache_capacity: usize, } #[derive(Serialize, Deserialize, Debug)] @@ -60,9 +61,12 @@ pub struct State { } impl State { - pub fn new() -> Self { + pub fn new(key_cache_capacity: usize) -> Self { let provider_kp = SignKeyPair::new(); - let dnscrypt_encryption_params_set = vec![DNSCryptEncryptionParams::new(&provider_kp)]; + let dnscrypt_encryption_params_set = vec![DNSCryptEncryptionParams::new( + &provider_kp, + key_cache_capacity, + )]; State { provider_kp, dnscrypt_encryption_params_set, @@ -82,11 +86,14 @@ impl State { Ok(()) } - pub fn from_file>(path: P) -> Result { + pub fn from_file>(path: P, key_cache_capacity: usize) -> Result { let mut fp = File::open(path.as_ref())?; let mut state_bin = vec![]; fp.read_to_end(&mut state_bin)?; - let state = toml::from_slice(&state_bin)?; + let mut state: State = toml::from_slice(&state_bin)?; + for params_set in &mut state.dnscrypt_encryption_params_set { + params_set.add_key_cache(key_cache_capacity); + } Ok(state) } } diff --git a/src/dnscrypt.rs b/src/dnscrypt.rs index 4a1c9de..02abed5 100644 --- a/src/dnscrypt.rs +++ b/src/dnscrypt.rs @@ -65,8 +65,31 @@ pub fn decrypt( let mut nonce = [0u8; DNSCRYPT_FULL_NONCE_SIZE as usize]; nonce[..DNSCRYPT_QUERY_NONCE_SIZE].copy_from_slice(client_nonce); - let resolver_kp = dnscrypt_encryption_params.resolver_kp(); - let shared_key = resolver_kp.compute_shared_key(client_pk)?; + + let cached_shared_key = { + let mut cache = dnscrypt_encryption_params.cache.as_ref().unwrap().lock(); + match cache.get(&client_pk[..]) { + None => None, + Some(cached_shared_key) => Some((*cached_shared_key).clone()), + } + }; + let shared_key = match cached_shared_key { + Some(cached_shared_key) => cached_shared_key, + None => { + let shared_key = dnscrypt_encryption_params + .resolver_kp() + .compute_shared_key(client_pk)?; + let mut client_pk_ = [0u8; DNSCRYPT_QUERY_PK_SIZE]; + client_pk_.copy_from_slice(&client_pk[..]); + dnscrypt_encryption_params + .cache + .as_ref() + .unwrap() + .lock() + .insert(client_pk_, shared_key.clone()); + shared_key + } + }; let packet = shared_key.decrypt(&nonce, encrypted_packet)?; rand::thread_rng().fill_bytes(&mut nonce[DNSCRYPT_QUERY_NONCE_SIZE..]); diff --git a/src/dnscrypt_certs.rs b/src/dnscrypt_certs.rs index a42c3fe..7136cda 100644 --- a/src/dnscrypt_certs.rs +++ b/src/dnscrypt_certs.rs @@ -1,9 +1,13 @@ use crate::config::*; use crate::crypto::*; +use crate::dnscrypt::*; +use crate::errors::*; use crate::globals::*; use byteorder::{BigEndian, ByteOrder}; +use clockpro_cache::ClockProCache; use coarsetime::Clock; +use parking_lot::Mutex; use std::mem; use std::slice; use std::sync::Arc; @@ -90,22 +94,33 @@ impl DNSCryptCert { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Clone, Derivative)] +#[derivative(Debug)] pub struct DNSCryptEncryptionParams { dnscrypt_cert: DNSCryptCert, resolver_kp: CryptKeyPair, + #[serde(skip)] + #[derivative(Debug = "ignore")] + pub cache: Option>>>, } impl DNSCryptEncryptionParams { - pub fn new(provider_kp: &SignKeyPair) -> Self { + pub fn new(provider_kp: &SignKeyPair, cache_capacity: usize) -> Self { let resolver_kp = CryptKeyPair::new(); let dnscrypt_cert = DNSCryptCert::new(&provider_kp, &resolver_kp); + let cache = ClockProCache::new(cache_capacity).unwrap(); DNSCryptEncryptionParams { dnscrypt_cert, resolver_kp, + cache: Some(Arc::new(Mutex::new(cache))), } } + pub fn add_key_cache(&mut self, cache_capacity: usize) { + let cache = ClockProCache::new(cache_capacity).unwrap(); + self.cache = Some(Arc::new(Mutex::new(cache))); + } + pub fn client_magic(&self) -> &[u8] { self.dnscrypt_cert.client_magic() } @@ -139,7 +154,10 @@ impl DNSCryptEncryptionParamsUpdater { } } } - let new_params = DNSCryptEncryptionParams::new(&self.globals.provider_kp); + let new_params = DNSCryptEncryptionParams::new( + &self.globals.provider_kp, + self.globals.key_cache_capacity, + ); new_params_set.push(Arc::new(new_params)); let state = State { provider_kp: self.globals.provider_kp.clone(), @@ -150,6 +168,7 @@ impl DNSCryptEncryptionParamsUpdater { let _ = state.async_save(state_file).await; }); *self.globals.dnscrypt_encryption_params_set.write() = Arc::new(new_params_set); + debug!("New certificate issued"); } pub async fn run(self) { diff --git a/src/globals.rs b/src/globals.rs index 3cae7e4..33650b8 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -30,4 +30,5 @@ pub struct Globals { pub tcp_max_active_connections: u32, pub udp_active_connections: Arc>>>, pub tcp_active_connections: Arc>>>, + pub key_cache_capacity: usize, } diff --git a/src/main.rs b/src/main.rs index 5dbd812..35b1f15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -369,7 +369,13 @@ async fn start(globals: Arc, runtime: Arc) -> Result<(), Error } fn main() -> Result<(), Error> { - env_logger::init(); + env_logger::Builder::from_default_env() + .default_format_module_path(false) + .default_format_timestamp(false) + .filter_level(log::LevelFilter::Info) + .target(env_logger::Target::Stdout) + .init(); + crypto::init()?; let updater = coarsetime::Updater::new(1000).start()?; mem::forget(updater); @@ -414,16 +420,17 @@ fn main() -> Result<(), Error> { runtime_builder.name_prefix("encrypted-dns-"); let runtime = Arc::new(runtime_builder.build()?); + let key_cache_capacity = config.dnscrypt.key_cache_capacity; let state_file = &config.state_file; - let state = match State::from_file(state_file) { + let state = match State::from_file(state_file, key_cache_capacity) { Err(_) => { - println!("No state file found... creating a new provider key"); - let state = State::new(); + warn!("No state file found... creating a new provider key"); + let state = State::new(key_cache_capacity); runtime.block_on(state.async_save(state_file))?; state } Ok(state) => { - println!( + info!( "State file [{}] found; using existing provider key", state_file.as_os_str().to_string_lossy() ); @@ -445,7 +452,7 @@ fn main() -> Result<(), Error> { .with_informal_property(InformalProperty::NoLogs) .serialize() .unwrap(); - println!("DNS Stamp: {}", stamp); + info!("DNS Stamp: {}", stamp); } let dnscrypt_encryption_params_set = state .dnscrypt_encryption_params_set @@ -477,6 +484,7 @@ fn main() -> Result<(), Error> { tcp_active_connections: Arc::new(Mutex::new(VecDeque::with_capacity( config.tcp_max_active_connections as _, ))), + key_cache_capacity, }); let updater = DNSCryptEncryptionParamsUpdater::new(globals.clone()); runtime.spawn(updater.run());