diff --git a/bin/common/validator/mod.rs b/bin/common/validator/mod.rs index 224f56fa2e35..dc5b5cdfd6e9 100644 --- a/bin/common/validator/mod.rs +++ b/bin/common/validator/mod.rs @@ -4,6 +4,8 @@ use std::net::SocketAddr; +#[cfg(feature = "local-dns")] +use shadowsocks_service::local::dns::NameServerAddr; use shadowsocks_service::shadowsocks::{relay::socks5::Address, ManagerAddr, ServerAddr, ServerConfig}; macro_rules! validate_type { @@ -29,6 +31,11 @@ validate_type!( ManagerAddr, "should be either ip:port, domain:port or /path/to/unix.sock" ); +validate_type!( + validate_name_server_addr, + NameServerAddr, + "should be either ip:port or a path to unix domain socket" +); validate_type!(validate_u64, u64, "should be unsigned integer"); validate_type!(validate_u32, u32, "should be unsigned integer"); diff --git a/bin/sslocal.rs b/bin/sslocal.rs index e8e95740ae88..2994fa293b1f 100644 --- a/bin/sslocal.rs +++ b/bin/sslocal.rs @@ -142,7 +142,7 @@ fn main() { #[cfg(feature = "local-dns")] { app = clap_app!(@app (app) - (@arg LOCAL_DNS_ADDR: --("local-dns-addr") +takes_value required_if("PROTOCOL", "dns") {validator::validate_socket_addr} "Specify the address of local DNS server, send queries directly") + (@arg LOCAL_DNS_ADDR: --("local-dns-addr") +takes_value required_if("PROTOCOL", "dns") {validator::validate_name_server_addr} "Specify the address of local DNS server, send queries directly") (@arg REMOTE_DNS_ADDR: --("remote-dns-addr") +takes_value required_if("PROTOCOL", "dns") {validator::validate_address} "Specify the address of remote DNS server, send queries through shadowsocks' tunnel") (@arg DNS_LOCAL_ADDR: --("dns-addr") +takes_value requires_all(&["REMOTE_DNS_ADDR"]) {validator::validate_server_addr} "DNS address, listen to this address if specified") ); @@ -247,10 +247,10 @@ fn main() { #[cfg(feature = "local-dns")] { - use std::net::SocketAddr; + use shadowsocks_service::local::dns::NameServerAddr; if let Some(local_dns_addr) = matches.value_of("LOCAL_DNS_ADDR") { - let addr = local_dns_addr.parse::().expect("local dns address"); + let addr = local_dns_addr.parse::().expect("local dns address"); config.local_dns_addr = Some(addr); } diff --git a/crates/shadowsocks-service/src/config.rs b/crates/shadowsocks-service/src/config.rs index 2e89b2ab2707..b543ed61f4ef 100644 --- a/crates/shadowsocks-service/src/config.rs +++ b/crates/shadowsocks-service/src/config.rs @@ -70,6 +70,8 @@ use shadowsocks::{ use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig}; use crate::acl::AccessControl; +#[cfg(feature = "local-dns")] +use crate::local::dns::NameServerAddr; #[cfg(feature = "trust-dns")] #[derive(Serialize, Deserialize, Debug)] @@ -574,7 +576,7 @@ pub struct Config { /// /// Sending DNS query directly to this address #[cfg(feature = "local-dns")] - pub local_dns_addr: Option, + pub local_dns_addr: Option, /// Remote DNS's address /// /// Sending DNS query through proxy to this address diff --git a/crates/shadowsocks-service/src/local/dns/client_cache.rs b/crates/shadowsocks-service/src/local/dns/client_cache.rs index efc096971555..7eb1c59c8a40 100644 --- a/crates/shadowsocks-service/src/local/dns/client_cache.rs +++ b/crates/shadowsocks-service/src/local/dns/client_cache.rs @@ -121,7 +121,6 @@ impl DnsClientCache { } #[cfg(unix)] - #[allow(dead_code)] pub async fn lookup_unix_stream>(&self, ns: &P, msg: Message) -> Result { let mut last_err = None; diff --git a/crates/shadowsocks-service/src/local/dns/config.rs b/crates/shadowsocks-service/src/local/dns/config.rs new file mode 100644 index 000000000000..94efb243cadc --- /dev/null +++ b/crates/shadowsocks-service/src/local/dns/config.rs @@ -0,0 +1,52 @@ +//! DNS configurations + +#[cfg(unix)] +use std::{convert::Infallible, path::PathBuf}; +use std::{ + fmt::{self, Display}, + net::SocketAddr, + str::FromStr, +}; + +/// DNS name server address +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum NameServerAddr { + /// IP address + SocketAddr(SocketAddr), + /// Unix Domain Socket address + /// + /// Specifically used by Android, which served as a stream protocol based DNS server + #[cfg(unix)] + UnixSocketAddr(PathBuf), +} + +/// Parse `NameServerAddr` error +#[cfg(unix)] +pub type NameServerAddrError = Infallible; +/// Parse `NameServerAddr` error +#[cfg(not(unix))] +pub type NameServerAddrError = ::Err; + +impl FromStr for NameServerAddr { + type Err = NameServerAddrError; + + fn from_str(s: &str) -> Result { + match s.parse::() { + Ok(addr) => Ok(NameServerAddr::SocketAddr(addr)), + #[cfg(unix)] + Err(..) => Ok(NameServerAddr::UnixSocketAddr(PathBuf::from(s))), + #[cfg(not(unix))] + Err(err) => Err(err), + } + } +} + +impl Display for NameServerAddr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + NameServerAddr::SocketAddr(ref sa) => Display::fmt(sa, f), + #[cfg(unix)] + NameServerAddr::UnixSocketAddr(ref p) => write!(f, "{}", p.display()), + } + } +} diff --git a/crates/shadowsocks-service/src/local/dns/mod.rs b/crates/shadowsocks-service/src/local/dns/mod.rs index 77752387f4e0..7f644882265b 100644 --- a/crates/shadowsocks-service/src/local/dns/mod.rs +++ b/crates/shadowsocks-service/src/local/dns/mod.rs @@ -1,7 +1,8 @@ //! Customized DNS resolver -pub use self::server::Dns; +pub use self::{config::NameServerAddr, server::Dns}; mod client_cache; +pub mod config; pub mod server; mod upstream; diff --git a/crates/shadowsocks-service/src/local/dns/server.rs b/crates/shadowsocks-service/src/local/dns/server.rs index 9786b2a97399..65255bca6a67 100644 --- a/crates/shadowsocks-service/src/local/dns/server.rs +++ b/crates/shadowsocks-service/src/local/dns/server.rs @@ -36,29 +36,29 @@ use crate::{ local::{context::ServiceContext, loadbalancing::PingBalancer}, }; -use super::client_cache::DnsClientCache; +use super::{client_cache::DnsClientCache, config::NameServerAddr}; /// DNS Relay server pub struct Dns { context: Arc, mode: Mode, - local_addr: SocketAddr, + local_addr: Arc, remote_addr: Arc
, } impl Dns { /// Create a new DNS Relay server - pub fn new(local_addr: SocketAddr, remote_addr: Address) -> Dns { + pub fn new(local_addr: NameServerAddr, remote_addr: Address) -> Dns { let context = ServiceContext::new(); Dns::with_context(Arc::new(context), local_addr, remote_addr) } /// Create with an existed `context` - pub fn with_context(context: Arc, local_addr: SocketAddr, remote_addr: Address) -> Dns { + pub fn with_context(context: Arc, local_addr: NameServerAddr, remote_addr: Address) -> Dns { Dns { context, mode: Mode::UdpOnly, - local_addr: local_addr, + local_addr: Arc::new(local_addr), remote_addr: Arc::new(remote_addr), } } @@ -117,7 +117,7 @@ impl Dns { client.clone(), stream, peer_addr, - self.local_addr, + self.local_addr.clone(), self.remote_addr.clone(), )); } @@ -127,7 +127,7 @@ impl Dns { client: Arc, mut stream: TcpStream, peer_addr: SocketAddr, - local_addr: SocketAddr, + local_addr: Arc, remote_addr: Arc
, ) -> io::Result<()> { let mut length_buf = [0u8; 2]; @@ -168,7 +168,7 @@ impl Dns { } }; - let respond_message = match client.resolve(message, local_addr, &remote_addr).await { + let respond_message = match client.resolve(message, &local_addr, &remote_addr).await { Ok(m) => m, Err(err) => { error!("dns tcp {} lookup error: {}", peer_addr, err); @@ -237,7 +237,7 @@ impl Dns { listener.clone(), peer_addr, message, - self.local_addr, + self.local_addr.clone(), self.remote_addr.clone(), )); } @@ -248,10 +248,10 @@ impl Dns { listener: Arc, peer_addr: SocketAddr, message: Message, - local_addr: SocketAddr, + local_addr: Arc, remote_addr: Arc
, ) -> io::Result<()> { - let respond_message = match client.resolve(message, local_addr, &remote_addr).await { + let respond_message = match client.resolve(message, &local_addr, &remote_addr).await { Ok(m) => m, Err(err) => { error!("dns udp {} lookup failed, error: {}", peer_addr, err); @@ -442,7 +442,12 @@ impl DnsClient { } } - async fn resolve(&self, request: Message, local_addr: SocketAddr, remote_addr: &Address) -> io::Result { + async fn resolve( + &self, + request: Message, + local_addr: &NameServerAddr, + remote_addr: &Address, + ) -> io::Result { let mut message = Message::new(); message.set_id(request.id()); message.set_recursion_desired(true); @@ -476,7 +481,7 @@ impl DnsClient { async fn acl_lookup( &self, query: &Query, - local_addr: SocketAddr, + local_addr: &NameServerAddr, remote_addr: &Address, ) -> (io::Result, bool) { // Start querying name servers @@ -657,7 +662,7 @@ impl DnsClient { } } - async fn lookup_local(&self, query: &Query, local_addr: SocketAddr) -> io::Result { + async fn lookup_local(&self, query: &Query, local_addr: &NameServerAddr) -> io::Result { let mut last_err = io::Error::new(ErrorKind::InvalidData, "resolve empty"); for _ in 0..self.attempts { @@ -672,34 +677,44 @@ impl DnsClient { Err(last_err) } - async fn lookup_local_inner(&self, query: &Query, local_addr: SocketAddr) -> io::Result { + async fn lookup_local_inner(&self, query: &Query, local_addr: &NameServerAddr) -> io::Result { let mut message = Message::new(); message.set_id(thread_rng().gen()); message.set_recursion_desired(true); message.add_query(query.clone()); - // Query UDP then TCP + match *local_addr { + NameServerAddr::SocketAddr(ns) => { + // Query UDP then TCP - let udp_query = - self.client_cache - .lookup_udp_local(local_addr, message.clone(), self.context.connect_opts_ref()); - let tcp_query = async move { - // Send TCP query after 500ms, because UDP will always return faster than TCP, there is no need to send queries simutaneously - time::sleep(Duration::from_millis(500)).await; + let udp_query = + self.client_cache + .lookup_udp_local(ns, message.clone(), self.context.connect_opts_ref()); + let tcp_query = async move { + // Send TCP query after 500ms, because UDP will always return faster than TCP, there is no need to send queries simutaneously + time::sleep(Duration::from_millis(500)).await; - self.client_cache - .lookup_tcp_local(local_addr, message, self.context.connect_opts_ref()) - .await - }; + self.client_cache + .lookup_tcp_local(ns, message, self.context.connect_opts_ref()) + .await + }; - tokio::pin!(udp_query); - tokio::pin!(tcp_query); + tokio::pin!(udp_query); + tokio::pin!(tcp_query); - match future::select(udp_query, tcp_query).await { - Either::Left((Ok(m), ..)) => Ok(m), - Either::Left((Err(..), next)) => next.await.map_err(From::from), - Either::Right((Ok(m), ..)) => Ok(m), - Either::Right((Err(..), next)) => next.await.map_err(From::from), + match future::select(udp_query, tcp_query).await { + Either::Left((Ok(m), ..)) => Ok(m), + Either::Left((Err(..), next)) => next.await.map_err(From::from), + Either::Right((Ok(m), ..)) => Ok(m), + Either::Right((Err(..), next)) => next.await.map_err(From::from), + } + } + #[cfg(unix)] + NameServerAddr::UnixSocketAddr(ref path) => self + .client_cache + .lookup_unix_stream(path, message) + .await + .map_err(From::from), } } } diff --git a/crates/shadowsocks-service/src/local/mod.rs b/crates/shadowsocks-service/src/local/mod.rs index e153c261da27..4e2ee7392393 100644 --- a/crates/shadowsocks-service/src/local/mod.rs +++ b/crates/shadowsocks-service/src/local/mod.rs @@ -82,44 +82,44 @@ pub async fn run(mut config: Config) -> io::Result<()> { accept_opts.tcp.recv_buffer_size = config.inbound_recv_buffer_size; accept_opts.tcp.nodelay = config.no_delay; - #[cfg(all(feature = "local-dns", feature = "trust-dns"))] - if let Some(socket_addr) = config.local_dns_addr { - use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig}; - - trace!("initializing direct DNS resolver for {}", socket_addr); - - let mut resolver_config = ResolverConfig::new(); - - resolver_config.add_name_server(NameServerConfig { - socket_addr, - protocol: Protocol::Udp, - tls_dns_name: None, - trust_nx_responses: false, - #[cfg(feature = "dns-over-tls")] - tls_config: None, - }); - resolver_config.add_name_server(NameServerConfig { - socket_addr, - protocol: Protocol::Tcp, - tls_dns_name: None, - trust_nx_responses: false, - #[cfg(feature = "dns-over-tls")] - tls_config: None, - }); - - match DnsResolver::trust_dns_resolver(Some(resolver_config), config.ipv6_first).await { - Ok(r) => { - context.set_dns_resolver(Arc::new(r)); - } - Err(err) => { - error!( - "initialize DNS resolver failed, nameserver: {}, error: {}", - socket_addr, err - ); - return Err(err); - } - } - } + // #[cfg(all(feature = "local-dns", feature = "trust-dns"))] + // if let Some(socket_addr) = config.local_dns_addr { + // use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig}; + // + // trace!("initializing direct DNS resolver for {}", socket_addr); + // + // let mut resolver_config = ResolverConfig::new(); + // + // resolver_config.add_name_server(NameServerConfig { + // socket_addr, + // protocol: Protocol::Udp, + // tls_dns_name: None, + // trust_nx_responses: false, + // #[cfg(feature = "dns-over-tls")] + // tls_config: None, + // }); + // resolver_config.add_name_server(NameServerConfig { + // socket_addr, + // protocol: Protocol::Tcp, + // tls_dns_name: None, + // trust_nx_responses: false, + // #[cfg(feature = "dns-over-tls")] + // tls_config: None, + // }); + // + // match DnsResolver::trust_dns_resolver(Some(resolver_config), config.ipv6_first).await { + // Ok(r) => { + // context.set_dns_resolver(Arc::new(r)); + // } + // Err(err) => { + // error!( + // "initialize DNS resolver failed, nameserver: {}, error: {}", + // socket_addr, err + // ); + // return Err(err); + // } + // } + // } #[cfg(feature = "trust-dns")] if context.dns_resolver().is_system_resolver() {