Skip to content

Commit 2a5d2ed

Browse files
committed
Optimized DNS resolving logic
1 parent 2a42daf commit 2a5d2ed

File tree

8 files changed

+177
-221
lines changed

8 files changed

+177
-221
lines changed

Cargo.lock

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "shadowsocks-rust"
3-
version = "1.6.6"
3+
version = "1.6.7"
44
authors = ["Y. T. CHUNG <[email protected]>"]
55
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
66
repository = "https://github.com/zonyitoo/shadowsocks-rust"

src/relay/dns_resolver.rs

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,70 @@
11
//! Asynchronous DNS resolver
22
3-
use std::io;
4-
use std::net::{IpAddr, ToSocketAddrs};
3+
use std::io::{self, ErrorKind};
4+
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
55

6-
use futures::future;
6+
use futures::{future, Future};
77

88
use futures_cpupool::CpuPool;
99

1010
use relay::{boxed_future, BoxIoFuture};
11+
use relay::Context;
1112

1213
lazy_static! {
1314
static ref GLOBAL_DNS_CPU_POOL: CpuPool = CpuPool::new_num_cpus();
1415
}
1516

16-
pub fn resolve(addr: &str) -> BoxIoFuture<Vec<IpAddr>> {
17+
pub fn resolve(addr: &str, port: u16, check_forbidden: bool) -> BoxIoFuture<Vec<SocketAddr>> {
1718
// FIXME: Sometimes addr is actually an IpAddr!
1819
if let Ok(addr) = addr.parse::<IpAddr>() {
19-
return boxed_future(future::finished(vec![addr]));
20-
}
20+
if !check_forbidden {
21+
return boxed_future(future::finished(vec![SocketAddr::new(addr, port)]));
22+
}
2123

22-
trace!("Going to resolve \"{}\"", addr);
23-
let owned_addr = format!("{}:0", addr);
24+
let result = Context::with(move |ctx| {
25+
let forbidden_ip = &ctx.forbidden_ip();
2426

25-
let fut = GLOBAL_DNS_CPU_POOL.spawn_fn(move || {
26-
owned_addr.to_socket_addrs().and_then(|addr_iter| {
27-
let v = addr_iter.map(|addr| addr.ip()).collect::<Vec<IpAddr>>();
28-
if v.is_empty() {
29-
let err = io::Error::new(io::ErrorKind::Other, format!("Failed to resolve \"{}\"", owned_addr));
27+
if forbidden_ip.contains(&addr) {
28+
let err = io::Error::new(ErrorKind::Other, format!("{} is forbidden, all IPs are filtered", addr));
3029
Err(err)
3130
} else {
32-
trace!("Resolved \"{}\" => {:?}", owned_addr, v);
33-
Ok(v)
31+
Ok(vec![SocketAddr::new(addr, port)])
3432
}
35-
})
33+
});
34+
35+
return boxed_future(future::done(result));
36+
}
37+
38+
trace!("Going to resolve \"{}:{}\"", addr, port);
39+
let owned_addr = addr.to_owned();
40+
let fut = GLOBAL_DNS_CPU_POOL.spawn_fn(move || {
41+
(owned_addr.as_str(), port).to_socket_addrs()
42+
.map(|a| (owned_addr, a))
43+
})
44+
.and_then(move |(owned_addr, addr_iter)| {
45+
let v = if !check_forbidden {
46+
addr_iter.collect::<Vec<SocketAddr>>()
47+
} else {
48+
Context::with(move |ctx| {
49+
let forbidden_ip = ctx.forbidden_ip();
50+
addr_iter.filter(|addr| {
51+
let filtered = forbidden_ip.contains(&addr.ip());
52+
if filtered {
53+
error!("{} is forbidden", addr.ip());
54+
}
55+
!filtered
56+
})
57+
.collect::<Vec<SocketAddr>>()
58+
})
59+
};
60+
61+
if v.is_empty() {
62+
let err = io::Error::new(io::ErrorKind::Other, format!("failed to resolve \"{}:{}\"", owned_addr, port));
63+
Err(err)
64+
} else {
65+
trace!("Resolved \"{}\" => {:?}", owned_addr, v);
66+
Ok(v)
67+
}
3668
});
3769

3870
boxed_future(fut)

src/relay/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Relay server in local and server side implementations.
22
3+
use std::collections::HashSet;
34
use std::io;
5+
use std::net::IpAddr;
46

57
use config::Config;
68
use futures::Future;
@@ -69,4 +71,9 @@ impl Context {
6971
pub fn config(&self) -> &Config {
7072
&self.config
7173
}
74+
75+
/// Get forbidden IPs
76+
pub fn forbidden_ip(&self) -> &HashSet<IpAddr> {
77+
&self.config.forbidden_ip
78+
}
7279
}

src/relay/tcprelay/mod.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
use std::io::{self, BufRead, Read};
44
use std::iter::{IntoIterator, Iterator};
55
use std::mem;
6-
use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
7-
use std::net::IpAddr;
6+
use std::net::SocketAddr;
87
use std::rc::Rc;
98
use std::time::Duration;
109

@@ -242,22 +241,10 @@ fn connect_proxy_server(svr_cfg: Rc<ServerConfig>) -> BoxIoFuture<TcpStream> {
242241
}
243242
ServerAddr::DomainName(ref domain, port) => {
244243
let fut = Context::with(|ctx| {
245-
let handle = ctx.handle();
246-
try_timeout(resolve(&domain[..]), timeout, &handle)
247-
}).and_then(move |vec_ipaddr| {
248-
Context::with(|ctx| {
249-
let handle = ctx.handle();
250-
251-
let it =
252-
vec_ipaddr.into_iter().map(move |ip| match ip {
253-
IpAddr::V4(v4) => SocketAddr::V4(SocketAddrV4::new(v4, port)),
254-
IpAddr::V6(v6) => {
255-
SocketAddr::V6(SocketAddrV6::new(v6, port, 0, 0))
256-
}
257-
});
258-
259-
let fut = TcpStreamConnect::new(it, handle);
260-
try_timeout(fut, timeout, handle)
244+
let handle = ctx.handle().clone();
245+
try_timeout(resolve(&domain[..], port, false), timeout, &handle).and_then(move |vec_ipaddr| {
246+
let fut = TcpStreamConnect::new(vec_ipaddr.into_iter(), &handle);
247+
try_timeout(fut, timeout, &handle)
261248
})
262249
});
263250
boxed_future(fut)

0 commit comments

Comments
 (0)