Skip to content

Commit

Permalink
trust-dns setsockopt with outbound socket configs
Browse files Browse the repository at this point in the history
Outbound configurations, like outbound-fwmark, outbound-bind-interface,
         outbound-bind-addr, ... will also applies to the TCP/UDP
         sockets created by trust-dns DNS resolver.

NOTE: On Android platform, DNS sockets will also be protected.
  • Loading branch information
zonyitoo committed Apr 15, 2023
1 parent c1f505f commit 2dff4ec
Show file tree
Hide file tree
Showing 17 changed files with 325 additions and 196 deletions.
190 changes: 86 additions & 104 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "shadowsocks-rust"
version = "1.15.3"
version = "1.16.0"
authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust"
Expand Down Expand Up @@ -167,7 +167,7 @@ jemallocator = { version = "0.5", optional = true }
snmalloc-rs = { version = "0.3", optional = true }
rpmalloc = { version = "0.2", optional = true }

shadowsocks-service = { version = "1.15.0", path = "./crates/shadowsocks-service" }
shadowsocks-service = { version = "1.16.0", path = "./crates/shadowsocks-service" }

[target.'cfg(unix)'.dependencies]
daemonize = "0.5"
Expand Down
7 changes: 4 additions & 3 deletions crates/shadowsocks-service/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "shadowsocks-service"
version = "1.15.3"
version = "1.16.0"
authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust"
Expand Down Expand Up @@ -107,7 +107,8 @@ libc = "0.2.141"
hyper = { version = "0.14.25", optional = true, features = ["full"] }
tower = { version = "0.4", optional = true }

trust-dns-resolver = { version = "0.22", optional = true, features = ["serde-config"] }
# trust-dns-resolver = { version = "0.22", optional = true, features = ["serde-config"] }
trust-dns-resolver = { git = "https://github.com/bluejekyll/trust-dns.git", optional = true, features = ["serde-config"] }

idna = "0.3"
ipnet = "2.7"
Expand All @@ -121,7 +122,7 @@ smoltcp = { version = "0.9", optional = true, default-features = false, features
serde = { version = "1.0", features = ["derive"] }
json5 = "0.4"

shadowsocks = { version = "1.15.3", path = "../shadowsocks", default-features = false }
shadowsocks = { version = "1.16.0", path = "../shadowsocks", default-features = false }

# Just for the ioctl call macro
[target.'cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies]
Expand Down
22 changes: 4 additions & 18 deletions crates/shadowsocks-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2112,26 +2112,12 @@ impl Config {
};

if protocol.enable_udp() {
c.add_name_server(NameServerConfig {
socket_addr,
protocol: Protocol::Udp,
tls_dns_name: None,
trust_nx_responses: false,
#[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))]
tls_config: None,
bind_addr: None,
});
let ns_config = NameServerConfig::new(socket_addr, Protocol::Udp);
c.add_name_server(ns_config);
}
if protocol.enable_tcp() {
c.add_name_server(NameServerConfig {
socket_addr,
protocol: Protocol::Tcp,
tls_dns_name: None,
trust_nx_responses: false,
#[cfg(any(feature = "dns-over-tls", feature = "dns-over-https"))]
tls_config: None,
bind_addr: None,
});
let ns_config = NameServerConfig::new(socket_addr, Protocol::Tcp);
c.add_name_server(ns_config);
}
}

Expand Down
4 changes: 2 additions & 2 deletions crates/shadowsocks-service/src/dns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub async fn build_dns_resolver(dns: DnsConfig, ipv6_first: bool, connect_opts:
};

if !force_system_builtin {
return match DnsResolver::trust_dns_system_resolver(ipv6_first).await {
return match DnsResolver::trust_dns_system_resolver(connect_opts.clone()).await {
Ok(r) => Some(r),
Err(err) => {
warn!(
Expand All @@ -41,7 +41,7 @@ pub async fn build_dns_resolver(dns: DnsConfig, ipv6_first: bool, connect_opts:
None
}
#[cfg(feature = "trust-dns")]
DnsConfig::TrustDns(dns) => match DnsResolver::trust_dns_resolver(dns, ipv6_first).await {
DnsConfig::TrustDns(dns) => match DnsResolver::trust_dns_resolver(dns, connect_opts.clone()).await {
Ok(r) => Some(r),
Err(err) => {
use log::warn;
Expand Down
6 changes: 3 additions & 3 deletions crates/shadowsocks-service/src/local/dns/dns_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use std::{
io::{self, ErrorKind},
net::SocketAddr,
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
};

use async_trait::async_trait;
Expand Down Expand Up @@ -175,8 +175,8 @@ fn store_dns(res: Message, port: u16) -> Vec<SocketAddr> {
let mut vaddr = Vec::new();
for record in res.answers() {
match record.data() {
Some(RData::A(addr)) => vaddr.push(SocketAddr::new((*addr).into(), port)),
Some(RData::AAAA(addr)) => vaddr.push(SocketAddr::new((*addr).into(), port)),
Some(RData::A(addr)) => vaddr.push(SocketAddr::new(Ipv4Addr::from(*addr).into(), port)),
Some(RData::AAAA(addr)) => vaddr.push(SocketAddr::new(Ipv6Addr::from(*addr).into(), port)),
Some(rdata) => {
trace!("skipped rdata {:?}", rdata);
}
Expand Down
16 changes: 12 additions & 4 deletions crates/shadowsocks-service/src/local/dns/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,8 @@ fn should_forward_by_response(
return true;
}
let forward = match $rec.data() {
Some(RData::A(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V4(*ip)),
Some(RData::AAAA(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V6(*ip)),
Some(RData::A(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V4((*ip).into())),
Some(RData::AAAA(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V6((*ip).into())),
// MX records cause type A additional section processing for the host specified by EXCHANGE.
Some(RData::MX(mx)) => examine_name!(mx.exchange(), $is_answer),
// NS records cause both the usual additional section processing to locate a type A record...
Expand Down Expand Up @@ -498,8 +498,16 @@ impl DnsClient {
for rec in result.answers() {
trace!("dns answer: {:?}", rec);
match rec.data() {
Some(RData::A(ip)) => self.context.add_to_reverse_lookup_cache((*ip).into(), forward).await,
Some(RData::AAAA(ip)) => self.context.add_to_reverse_lookup_cache((*ip).into(), forward).await,
Some(RData::A(ip)) => {
self.context
.add_to_reverse_lookup_cache(Ipv4Addr::from(*ip).into(), forward)
.await
}
Some(RData::AAAA(ip)) => {
self.context
.add_to_reverse_lookup_cache(Ipv6Addr::from(*ip).into(), forward)
.await
}
_ => (),
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/shadowsocks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "shadowsocks"
version = "1.15.3"
version = "1.16.0"
authors = ["Shadowsocks Contributors"]
description = "shadowsocks is a fast tunnel proxy that helps you bypass firewalls."
repository = "https://github.com/shadowsocks/shadowsocks-rust"
Expand Down Expand Up @@ -68,7 +68,8 @@ socket2 = { version = "0.5", features = ["all"] }
tokio = { version = "1.9.0", features = ["io-util", "macros", "net", "parking_lot", "process", "rt", "sync", "time"] }
tokio-tfo = "0.2.0"

trust-dns-resolver = { version = "0.22", optional = true }
# trust-dns-resolver = { version = "0.22", optional = true }
trust-dns-resolver = { git = "https://github.com/bluejekyll/trust-dns.git", optional = true }
arc-swap = { version = "1.6", optional = true }
notify = { version = "5.1.0", optional = true }

Expand Down
58 changes: 33 additions & 25 deletions crates/shadowsocks/src/dns_resolver/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@ use tokio::net::lookup_host;
#[cfg(feature = "trust-dns")]
use tokio::task::JoinHandle;
#[cfg(feature = "trust-dns")]
use trust_dns_resolver::{config::ResolverConfig, TokioAsyncResolver};
use trust_dns_resolver::config::ResolverConfig;

#[cfg(feature = "trust-dns")]
use crate::net::ConnectOpts;

#[cfg(feature = "trust-dns")]
use super::trust_dns_resolver::DnsResolver as TrustDnsResolver;

/// Abstract DNS resolver
#[async_trait]
Expand All @@ -31,8 +37,8 @@ pub trait DnsResolve {

#[cfg(feature = "trust-dns")]
pub struct TrustDnsSystemResolver {
resolver: ArcSwap<TokioAsyncResolver>,
ipv6_first: bool,
resolver: ArcSwap<TrustDnsResolver>,
connect_opts: ConnectOpts,
}

/// Collections of DNS resolver
Expand All @@ -44,11 +50,12 @@ pub enum DnsResolver {
#[cfg(feature = "trust-dns")]
TrustDnsSystem {
inner: Arc<TrustDnsSystemResolver>,
#[cfg(all(feature = "trust-dns", unix, not(target_os = "android")))]
abortable: JoinHandle<()>,
},
/// Trust-DNS resolver
#[cfg(feature = "trust-dns")]
TrustDns(TokioAsyncResolver),
TrustDns(TrustDnsResolver),
/// Customized Resolver
Custom(Box<dyn DnsResolve + Send + Sync>),
}
Expand All @@ -75,6 +82,7 @@ impl Debug for DnsResolver {
#[cfg(feature = "trust-dns")]
impl Drop for DnsResolver {
fn drop(&mut self) {
#[cfg(all(feature = "trust-dns", unix, not(target_os = "android")))]
if let DnsResolver::TrustDnsSystem { ref abortable, .. } = *self {
abortable.abort();
}
Expand Down Expand Up @@ -187,7 +195,7 @@ async fn trust_dns_notify_update_dns(resolver: Arc<TrustDnsSystemResolver>) -> n
// Update once for all those Modify events
time::sleep(Duration::from_secs(1)).await;

match create_resolver(None, resolver.ipv6_first).await {
match create_resolver(None, resolver.connect_opts.clone()).await {
Ok(r) => {
debug!("auto-reload {DNS_RESOLV_FILE_PATH}");

Expand All @@ -208,12 +216,6 @@ async fn trust_dns_notify_update_dns(resolver: Arc<TrustDnsSystemResolver>) -> n
Ok(())
}

#[cfg(all(feature = "trust-dns", any(not(unix), target_os = "android")))]
async fn trust_dns_notify_update_dns(resolver: Arc<TrustDnsSystemResolver>) -> notify::Result<()> {
let _ = resolver.ipv6_first; // use it for supressing warning
futures::future::pending().await
}

impl DnsResolver {
/// Use system DNS resolver. Tokio will call `getaddrinfo` in blocking pool.
pub fn system_resolver() -> DnsResolver {
Expand All @@ -224,33 +226,39 @@ impl DnsResolver {
///
/// On *nix system, it will try to read configurations from `/etc/resolv.conf`.
#[cfg(feature = "trust-dns")]
pub async fn trust_dns_system_resolver(ipv6_first: bool) -> io::Result<DnsResolver> {
pub async fn trust_dns_system_resolver(connect_opts: ConnectOpts) -> io::Result<DnsResolver> {
use super::trust_dns_resolver::create_resolver;

let resolver = create_resolver(None, ipv6_first).await?;
let resolver = create_resolver(None, connect_opts.clone()).await?;

let inner = Arc::new(TrustDnsSystemResolver {
resolver: ArcSwap::from(Arc::new(resolver)),
ipv6_first,
connect_opts,
});

let abortable = {
let inner = inner.clone();
tokio::spawn(async {
if let Err(err) = trust_dns_notify_update_dns(inner).await {
error!("failed to watch DNS system configuration changes, error: {}", err);
}
})
};
cfg_if! {
if #[cfg(all(feature = "trust-dns", unix, not(target_os = "android")))] {
let abortable = {
let inner = inner.clone();
tokio::spawn(async {
if let Err(err) = trust_dns_notify_update_dns(inner).await {
error!("failed to watch DNS system configuration changes, error: {}", err);
}
})
};

Ok(DnsResolver::TrustDnsSystem { inner, abortable })
Ok(DnsResolver::TrustDnsSystem { inner, abortable })
} else {
Ok(DnsResolver::TrustDnsSystem { inner })
}
}
}

/// Use trust-dns DNS resolver (with DNS cache)
#[cfg(feature = "trust-dns")]
pub async fn trust_dns_resolver(dns: ResolverConfig, ipv6_first: bool) -> io::Result<DnsResolver> {
pub async fn trust_dns_resolver(dns: ResolverConfig, connect_opts: ConnectOpts) -> io::Result<DnsResolver> {
use super::trust_dns_resolver::create_resolver;
Ok(DnsResolver::TrustDns(create_resolver(Some(dns), ipv6_first).await?))
Ok(DnsResolver::TrustDns(create_resolver(Some(dns), connect_opts).await?))
}

/// Custom DNS resolver
Expand Down
Loading

0 comments on commit 2dff4ec

Please sign in to comment.