@@ -7,16 +7,17 @@ use std::{
7
7
atomic:: { AtomicBool , Ordering } ,
8
8
Arc ,
9
9
} ,
10
+ time:: Duration ,
10
11
} ;
11
12
12
13
#[ cfg( feature = "local-dns-relay" ) ]
13
- use std:: { net:: IpAddr , time :: Duration } ;
14
+ use std:: net:: IpAddr ;
14
15
15
16
use bloomfilter:: Bloom ;
16
- use log:: { log_enabled, warn} ;
17
- #[ cfg( feature = "local-dns-relay" ) ]
17
+ use log:: { log_enabled, trace, warn} ;
18
18
use lru_time_cache:: LruCache ;
19
- use spin:: Mutex ;
19
+ use spin:: Mutex as SpinMutex ;
20
+ use tokio:: sync:: Mutex as AsyncMutex ;
20
21
#[ cfg( feature = "trust-dns" ) ]
21
22
use trust_dns_resolver:: TokioAsyncResolver ;
22
23
@@ -171,19 +172,22 @@ pub struct Context {
171
172
172
173
// Check for duplicated IV/Nonce, for prevent replay attack
173
174
// https://github.com/shadowsocks/shadowsocks-org/issues/44
174
- nonce_ppbloom : Mutex < PingPongBloom > ,
175
+ nonce_ppbloom : SpinMutex < PingPongBloom > ,
175
176
176
177
// For Android's flow stat report
177
178
#[ cfg( feature = "local-flow-stat" ) ]
178
179
local_flow_statistic : ServerFlowStatistic ,
179
180
180
181
// For DNS relay's ACL domain name reverse lookup -- whether the IP shall be forwarded
181
182
#[ cfg( feature = "local-dns-relay" ) ]
182
- reverse_lookup_cache : Mutex < LruCache < IpAddr , bool > > ,
183
+ reverse_lookup_cache : AsyncMutex < LruCache < IpAddr , bool > > ,
183
184
184
185
// For local DNS upstream
185
186
#[ cfg( feature = "local-dns-relay" ) ]
186
187
local_dns : LocalUpstream ,
188
+
189
+ // ACL check result cache
190
+ acl_check_cache : AsyncMutex < LruCache < Address , bool > > ,
187
191
}
188
192
189
193
/// Unique context thw whole server
@@ -224,11 +228,7 @@ impl Context {
224
228
}
225
229
}
226
230
227
- let nonce_ppbloom = Mutex :: new ( PingPongBloom :: new ( config. config_type ) ) ;
228
- #[ cfg( feature = "local-dns-relay" ) ]
229
- let reverse_lookup_cache = Mutex :: new ( LruCache :: < IpAddr , bool > :: with_expiry_duration ( Duration :: from_secs (
230
- 3 * 24 * 60 * 60 ,
231
- ) ) ) ;
231
+ let nonce_ppbloom = SpinMutex :: new ( PingPongBloom :: new ( config. config_type ) ) ;
232
232
#[ cfg( feature = "local-dns-relay" ) ]
233
233
let local_dns = LocalUpstream :: new ( & config) ;
234
234
@@ -240,9 +240,15 @@ impl Context {
240
240
#[ cfg( feature = "local-flow-stat" ) ]
241
241
local_flow_statistic : ServerFlowStatistic :: new ( ) ,
242
242
#[ cfg( feature = "local-dns-relay" ) ]
243
- reverse_lookup_cache,
243
+ reverse_lookup_cache : AsyncMutex :: new ( LruCache :: with_expiry_duration ( Duration :: from_secs (
244
+ 3 * 24 * 60 * 60 ,
245
+ ) ) ) ,
244
246
#[ cfg( feature = "local-dns-relay" ) ]
245
247
local_dns,
248
+ acl_check_cache : AsyncMutex :: new ( LruCache :: with_expiry_duration_and_capacity (
249
+ Duration :: from_secs ( 24 * 60 * 60 ) ,
250
+ 512 ,
251
+ ) ) ,
246
252
}
247
253
}
248
254
@@ -376,14 +382,14 @@ impl Context {
376
382
377
383
/// Add a record to the reverse lookup cache
378
384
#[ cfg( feature = "local-dns-relay" ) ]
379
- pub fn add_to_reverse_lookup_cache ( & self , addr : & IpAddr , forward : bool ) {
385
+ pub async fn add_to_reverse_lookup_cache ( & self , addr : & IpAddr , forward : bool ) {
380
386
let is_exception = forward
381
387
!= match self . acl ( ) {
382
388
// Proxy everything by default
383
389
None => true ,
384
390
Some ( a) => a. check_ip_in_proxy_list ( addr) ,
385
391
} ;
386
- let mut reverse_lookup_cache = self . reverse_lookup_cache . lock ( ) ;
392
+ let mut reverse_lookup_cache = self . reverse_lookup_cache . lock ( ) . await ;
387
393
match reverse_lookup_cache. get_mut ( addr) {
388
394
Some ( value) => {
389
395
if is_exception {
@@ -453,7 +459,23 @@ impl Context {
453
459
}
454
460
}
455
461
}
456
- a. check_target_bypassed ( self , target) . await
462
+
463
+ // ACL checking may need over 500ms (DNS resolving)
464
+ if let Some ( bypassed) = self . acl_check_cache . lock ( ) . await . get ( target) {
465
+ trace ! (
466
+ "check bypassing {} cached result: {}" ,
467
+ target,
468
+ if * bypassed { "bypassed" } else { "proxied" }
469
+ ) ;
470
+
471
+ return * bypassed;
472
+ }
473
+
474
+ let r = a. check_target_bypassed ( self , target) . await ;
475
+
476
+ self . acl_check_cache . lock ( ) . await . insert ( target. clone ( ) , r) ;
477
+
478
+ r
457
479
}
458
480
459
481
/// Get client flow statistics
0 commit comments