diff --git a/Cargo.lock b/Cargo.lock index cfbf2255..29692dee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,7 @@ dependencies = [ "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lru_time_cache 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -313,6 +314,11 @@ dependencies = [ "linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lru_time_cache" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lzw" version = "0.10.0" @@ -713,6 +719,7 @@ dependencies = [ "checksum linked-hash-map 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bda158e0dabeb97ee8a401f4d17e479d6b891a14de0bba79d5cc2d4d325b5e48" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" "checksum lru-cache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "656fa4dfcb02bcf1063c592ba3ff6a5303ee1f2afe98c8a889e8b1a77c6dfdb7" +"checksum lru_time_cache 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf17862cdf1a87c7cc0cccc498552f3e564d2ae61069f83d2279a932af4a00c" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum mio 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aa30e3753079b08ce3d75cf3b44783e36fe0e1f64065f65c1d894d1688fb2580" diff --git a/Cargo.toml b/Cargo.toml index 5646c369..a99fd59e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shadowsocks-rust" -version = "1.3.1" +version = "1.3.2" authors = ["Y. T. CHUNG "] description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls." repository = "https://github.com/zonyitoo/shadowsocks-rust" @@ -38,6 +38,7 @@ env_logger = "0.4" rust-crypto = "0.2" openssl = "0.9" lru-cache = "0.1" +lru_time_cache = "0.6" libc = "0.2" futures = "0.1" tokio-core = "0.1" diff --git a/src/lib.rs b/src/lib.rs index c7601f25..b58435cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,7 @@ extern crate serde_json; #[macro_use] extern crate log; extern crate lru_cache; +extern crate lru_time_cache; extern crate byteorder; extern crate rand; diff --git a/src/relay/dns_resolver.rs b/src/relay/dns_resolver.rs index 471ff17b..ea17da1d 100644 --- a/src/relay/dns_resolver.rs +++ b/src/relay/dns_resolver.rs @@ -1,6 +1,8 @@ //! Asynchronous DNS resolver use std::io; +use std::time::Duration; +use std::cell::RefCell; use futures::{Future, BoxFuture}; use futures::future; @@ -11,13 +13,28 @@ use domain::resolv::Resolver; use domain::resolv::lookup::lookup_host; use domain::bits::DNameBuf; +use lru_time_cache::LruCache; + use std::net::IpAddr; +// Global DNS cache. +// Cache for 5mins and store at most 128 entries +thread_local!(static GLOBAL_DNS_CACHE: RefCell> + = RefCell::new(LruCache::with_expiry_duration_and_capacity(Duration::from_secs(5 * 60), 128))); + pub fn resolve(addr: &str, handle: &Handle) -> BoxFuture { + let cached_addr = GLOBAL_DNS_CACHE.with(|c| { + let mut xc = c.borrow_mut(); + xc.get(addr).map(|x| *x) + }); + + if let Some(addr) = cached_addr { + return future::finished(addr).boxed(); + } + let dname = match addr.parse::() { Ok(dname) => dname, - Err(err) => return future::err(io::Error::new(io::ErrorKind::Other, err)) - .boxed() + Err(err) => return future::err(io::Error::new(io::ErrorKind::Other, err)).boxed(), }; let resolv = Resolver::new(handle); @@ -25,18 +42,22 @@ pub fn resolve(addr: &str, handle: &Handle) -> BoxFuture { lookup_host(resolv, &dname) .map_err(From::from) - .and_then(move |hosts| { - match hosts.iter().next() { - Some(addr) => { - trace!("Resolved \"{}\" as {}", dname, addr); - Ok(addr) - } - None => { - let err = io::Error::new(io::ErrorKind::Other, - format!("Failed to resolve \"{}\"", dname)); - Err(err) - } - } - }) + .and_then(move |hosts| match hosts.iter().next() { + Some(addr) => { + trace!("Resolved \"{}\" as {}", dname, addr); + + GLOBAL_DNS_CACHE.with(|c| { + let mut xc = c.borrow_mut(); + xc.insert(dname.to_string(), addr); + }); + + Ok(addr) + } + None => { + let err = io::Error::new(io::ErrorKind::Other, + format!("Failed to resolve \"{}\"", dname)); + Err(err) + } + }) .boxed() }