Add a simple built-in DNS cache

(TTL is not handled yet)
pull/5/head
Frank Denis 5 years ago
parent cf1cbdb51d
commit c98a202f80

@ -31,7 +31,7 @@ rand = "0.7.2"
serde = "1.0.101"
serde_derive = "1.0.101"
serde-big-array = "0.1.5"
siphasher = "0.3.0"
siphasher = "0.3.1"
tokio = "=0.2.0-alpha.4"
tokio-net = "=0.2.0-alpha.4"
toml = "0.5.3"

@ -50,6 +50,11 @@ udp_max_active_connections = 1000
tcp_max_active_connections = 100
## DNS cache capacity
cache_capacity = 10000
## User name to drop privileges to, when started as root.
# user = "nobody"

@ -30,6 +30,7 @@ pub struct Config {
pub tcp_timeout: u32,
pub udp_max_active_connections: u32,
pub tcp_max_active_connections: u32,
pub cache_capacity: usize,
pub user: Option<String>,
pub group: Option<String>,
pub chroot: Option<String>,

@ -18,6 +18,18 @@ const DNS_TYPE_OPT: u16 = 41;
const DNS_TYPE_TXT: u16 = 16;
const DNS_CLASS_INET: u16 = 1;
const DNS_RCODE_SERVFAIL: u8 = 2;
#[inline]
pub fn rcode(packet: &[u8]) -> u8 {
packet[3] & 0x0f
}
#[inline]
pub fn rcode_servfail(packet: &[u8]) -> bool {
rcode(packet) == DNS_RCODE_SERVFAIL
}
#[inline]
pub fn qdcount(packet: &[u8]) -> u16 {
BigEndian::read_u16(&packet[4..])

@ -1,7 +1,9 @@
use crate::crypto::*;
use crate::dnscrypt_certs::*;
use clockpro_cache::ClockProCache;
use parking_lot::{Mutex, RwLock};
use siphasher::sip128::SipHasher13;
use std::collections::vec_deque::VecDeque;
use std::net::SocketAddr;
use std::path::PathBuf;
@ -11,7 +13,8 @@ use std::time::Duration;
use tokio::runtime::Runtime;
use tokio::sync::oneshot;
#[derive(Debug)]
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Globals {
pub runtime: Arc<Runtime>,
pub state_file: PathBuf,
@ -31,4 +34,7 @@ pub struct Globals {
pub udp_active_connections: Arc<Mutex<VecDeque<oneshot::Sender<()>>>>,
pub tcp_active_connections: Arc<Mutex<VecDeque<oneshot::Sender<()>>>>,
pub key_cache_capacity: usize,
pub hasher: SipHasher13,
#[derivative(Debug = "ignore")]
pub cache: Arc<Mutex<ClockProCache<u128, Vec<u8>>>>,
}

@ -36,6 +36,7 @@ use globals::*;
use byteorder::{BigEndian, ByteOrder};
use clap::Arg;
use clockpro_cache::ClockProCache;
use dnsstamps::{InformalProperty, WithInformalProperty};
use failure::{bail, ensure};
use futures::join;
@ -44,9 +45,11 @@ use parking_lot::Mutex;
use parking_lot::RwLock;
use privdrop::PrivDrop;
use rand::prelude::*;
use siphasher::sip128::{Hasher128, SipHasher13};
use std::collections::vec_deque::VecDeque;
use std::convert::TryFrom;
use std::fs::File;
use std::hash::Hasher;
use std::io::prelude::*;
use std::mem;
use std::net::SocketAddr;
@ -140,6 +143,21 @@ async fn respond_to_query(
async fn resolve(globals: &Globals, mut packet: &mut Vec<u8>) -> Result<Vec<u8>, Error> {
let original_tid = dns::tid(&packet);
dns::set_tid(&mut packet, 0);
let mut hasher = globals.hasher.clone();
hasher.write(&packet);
let packet_hash = hasher.finish128().as_u128();
let cached_response = {
match globals.cache.lock().get(&packet_hash) {
None => None,
Some(response) => Some((*response).clone()),
}
};
if let Some(mut cached_response) = cached_response {
dns::set_tid(&mut cached_response, original_tid);
return Ok(cached_response);
}
let tid = random();
dns::set_tid(&mut packet, tid);
let mut ext_socket = UdpSocket::bind(&globals.external_addr).await?;
@ -189,6 +207,9 @@ async fn resolve(globals: &Globals, mut packet: &mut Vec<u8>) -> Result<Vec<u8>,
"Unexpected query name in the response"
);
}
if !dns::rcode_servfail(&response) {
globals.cache.lock().insert(packet_hash, response.clone());
}
dns::set_tid(&mut response, original_tid);
Ok(response)
}
@ -435,6 +456,7 @@ fn main() -> Result<(), Error> {
let runtime = Arc::new(runtime_builder.build()?);
let key_cache_capacity = config.dnscrypt.key_cache_capacity;
let cache_capacity = config.cache_capacity;
let state_file = &config.state_file;
if let Some(secret_key_path) = matches.value_of("import-from-dnscrypt-wrapper") {
@ -497,6 +519,12 @@ fn main() -> Result<(), Error> {
.map(Arc::new)
.collect::<Vec<_>>();
let (sh_k0, sh_k1) = rand::thread_rng().gen();
let hasher = SipHasher13::new_with_keys(sh_k0, sh_k1);
let cache = ClockProCache::new(cache_capacity)
.map_err(|e| format_err!("Unable to create the DNS cache: [{}]", e))?;
let globals = Arc::new(Globals {
runtime: runtime.clone(),
state_file: state_file.to_path_buf(),
@ -522,6 +550,8 @@ fn main() -> Result<(), Error> {
config.tcp_max_active_connections as _,
))),
key_cache_capacity,
hasher,
cache: Arc::new(Mutex::new(cache)),
});
let updater = DNSCryptEncryptionParamsUpdater::new(globals.clone());
runtime.spawn(updater.run());

Loading…
Cancel
Save