Skip to content

Commit

Permalink
Cache recently ACL checking results
Browse files Browse the repository at this point in the history
ACL checking may requires lots of calculation and network I/O (DNS resolution)
  • Loading branch information
zonyitoo committed Jun 14, 2020
1 parent d3e2922 commit 101a6f2
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 19 deletions.
52 changes: 37 additions & 15 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ use std::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};

#[cfg(feature = "local-dns-relay")]
use std::{net::IpAddr, time::Duration};
use std::net::IpAddr;

use bloomfilter::Bloom;
use log::{log_enabled, warn};
#[cfg(feature = "local-dns-relay")]
use log::{log_enabled, trace, warn};
use lru_time_cache::LruCache;
use spin::Mutex;
use spin::Mutex as SpinMutex;
use tokio::sync::Mutex as AsyncMutex;
#[cfg(feature = "trust-dns")]
use trust_dns_resolver::TokioAsyncResolver;

Expand Down Expand Up @@ -171,19 +172,22 @@ pub struct Context {

// Check for duplicated IV/Nonce, for prevent replay attack
// https://github.com/shadowsocks/shadowsocks-org/issues/44
nonce_ppbloom: Mutex<PingPongBloom>,
nonce_ppbloom: SpinMutex<PingPongBloom>,

// For Android's flow stat report
#[cfg(feature = "local-flow-stat")]
local_flow_statistic: ServerFlowStatistic,

// For DNS relay's ACL domain name reverse lookup -- whether the IP shall be forwarded
#[cfg(feature = "local-dns-relay")]
reverse_lookup_cache: Mutex<LruCache<IpAddr, bool>>,
reverse_lookup_cache: AsyncMutex<LruCache<IpAddr, bool>>,

// For local DNS upstream
#[cfg(feature = "local-dns-relay")]
local_dns: LocalUpstream,

// ACL check result cache
acl_check_cache: AsyncMutex<LruCache<Address, bool>>,
}

/// Unique context thw whole server
Expand Down Expand Up @@ -224,11 +228,7 @@ impl Context {
}
}

let nonce_ppbloom = Mutex::new(PingPongBloom::new(config.config_type));
#[cfg(feature = "local-dns-relay")]
let reverse_lookup_cache = Mutex::new(LruCache::<IpAddr, bool>::with_expiry_duration(Duration::from_secs(
3 * 24 * 60 * 60,
)));
let nonce_ppbloom = SpinMutex::new(PingPongBloom::new(config.config_type));
#[cfg(feature = "local-dns-relay")]
let local_dns = LocalUpstream::new(&config);

Expand All @@ -240,9 +240,15 @@ impl Context {
#[cfg(feature = "local-flow-stat")]
local_flow_statistic: ServerFlowStatistic::new(),
#[cfg(feature = "local-dns-relay")]
reverse_lookup_cache,
reverse_lookup_cache: AsyncMutex::new(LruCache::with_expiry_duration(Duration::from_secs(
3 * 24 * 60 * 60,
))),
#[cfg(feature = "local-dns-relay")]
local_dns,
acl_check_cache: AsyncMutex::new(LruCache::with_expiry_duration_and_capacity(
Duration::from_secs(24 * 60 * 60),
512,
)),
}
}

Expand Down Expand Up @@ -376,14 +382,14 @@ impl Context {

/// Add a record to the reverse lookup cache
#[cfg(feature = "local-dns-relay")]
pub fn add_to_reverse_lookup_cache(&self, addr: &IpAddr, forward: bool) {
pub async fn add_to_reverse_lookup_cache(&self, addr: &IpAddr, forward: bool) {
let is_exception = forward
!= match self.acl() {
// Proxy everything by default
None => true,
Some(a) => a.check_ip_in_proxy_list(addr),
};
let mut reverse_lookup_cache = self.reverse_lookup_cache.lock();
let mut reverse_lookup_cache = self.reverse_lookup_cache.lock().await;
match reverse_lookup_cache.get_mut(addr) {
Some(value) => {
if is_exception {
Expand Down Expand Up @@ -453,7 +459,23 @@ impl Context {
}
}
}
a.check_target_bypassed(self, target).await

// ACL checking may need over 500ms (DNS resolving)
if let Some(bypassed) = self.acl_check_cache.lock().await.get(target) {
trace!(
"check bypassing {} cached result: {}",
target,
if *bypassed { "bypassed" } else { "proxied" }
);

return *bypassed;
}

let r = a.check_target_bypassed(self, target).await;

self.acl_check_cache.lock().await.insert(target.clone(), r);

r
}

/// Get client flow statistics
Expand Down
12 changes: 10 additions & 2 deletions src/relay/dnsrelay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,16 @@ impl<Remote: upstream::Upstream> DnsRelay<Remote> {
for rec in result.answers() {
debug!("dns answer: {:?}", rec);
match rec.rdata() {
RData::A(ref ip) => self.context.add_to_reverse_lookup_cache(&IpAddr::V4(*ip), forward),
RData::AAAA(ref ip) => self.context.add_to_reverse_lookup_cache(&IpAddr::V6(*ip), forward),
RData::A(ref ip) => {
self.context
.add_to_reverse_lookup_cache(&IpAddr::V4(*ip), forward)
.await
}
RData::AAAA(ref ip) => {
self.context
.add_to_reverse_lookup_cache(&IpAddr::V6(*ip), forward)
.await
}
_ => (),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/relay/socks4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl fmt::Display for ResultCode {
}

/// SOCKS4 Address type
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Address {
/// Socket address (IP Address)
SocketAddress(SocketAddrV4),
Expand Down
2 changes: 1 addition & 1 deletion src/relay/socks5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl From<Error> for io::Error {
}

/// SOCKS5 address type
#[derive(Clone, PartialEq, Eq, Hash)]
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum Address {
/// Socket address (IP Address)
SocketAddress(SocketAddr),
Expand Down

7 comments on commit 101a6f2

@dev4u
Copy link

@dev4u dev4u commented on 101a6f2 Jun 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be used for ss-android?

@zonyitoo
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes of course.

Compiliation issue is caused by libstd's version. It can only be compiled with rustc >= 1.46.0.

@dev4u
Copy link

@dev4u dev4u commented on 101a6f2 Jun 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was sad, when I compile the ss-android, I got a compilation issue.

error[E0599]: no method named get found for opaque type impl core::future::future::Future in the current scope
--> src/context.rs:457:61
|
457 | if let Some(forward) = reverse_lookup_cache.get(&saddr.ip()) {
| ^^^ method not found in impl core::future::future::Future

error: aborting due to previous error

please tell me, how can i fixed it?
P.S. rustc 1.46.0-nightly (feb3536eb 2020-06-09)

@zonyitoo
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try with the latest commit. Compile it with feature acl-check-cache

@Mygod
Copy link
Contributor

@Mygod Mygod commented on 101a6f2 Jun 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't latest stable release only 1.44.0? This means that it has to be compiled on nightly? That doesn't sound like a good thing.

@zonyitoo
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Mygod Yes. That's why I add a feature gate acl-check-cache.

@zonyitoo
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My fault, it seems that it will be released in 1.45: rust-lang/rust#72239

Please sign in to comment.