Skip to content

Commit

Permalink
feat(shadowsocks): upgrade hickory-dns to v0.25-alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
zonyitoo committed Nov 16, 2024
1 parent 9a6f40f commit a3ebc67
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 307 deletions.
343 changes: 88 additions & 255 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions crates/shadowsocks-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ dns-over-native-tls-vendored = [
]
dns-over-https = [
"hickory-dns",
"hickory-resolver/dns-over-https",
"hickory-resolver/dns-over-https-rustls",
"hickory-resolver/webpki-roots",
"hickory-resolver/native-certs",
Expand Down Expand Up @@ -182,8 +181,8 @@ http-body-util = { version = "0.1", optional = true }
http = { version = "1.1", optional = true }
httparse = { version = "1.9", optional = true }

hickory-resolver = { version = "0.24", optional = true, features = [
"serde-config",
hickory-resolver = { version = "0.25.0-alpha", optional = true, features = [
"serde",
] }

idna = "1.0"
Expand Down
4 changes: 3 additions & 1 deletion crates/shadowsocks-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use std::{

use cfg_if::cfg_if;
#[cfg(feature = "hickory-dns")]
use hickory_resolver::config::{NameServerConfig, Protocol, ResolverConfig};
use hickory_resolver::config::{NameServerConfig, ResolverConfig};
#[cfg(feature = "local-tun")]
use ipnet::IpNet;
#[cfg(feature = "local-fake-dns")]
Expand Down Expand Up @@ -2484,6 +2484,8 @@ impl Config {

#[cfg(any(feature = "hickory-dns", feature = "local-dns"))]
fn parse_dns_nameservers(&mut self, nameservers: &str) -> Result<DnsConfig, Error> {
use hickory_resolver::proto::xfer::Protocol;

#[cfg(all(unix, feature = "local-dns"))]
if let Some(nameservers) = nameservers.strip_prefix("unix://") {
// A special DNS server only for shadowsocks-android
Expand Down
2 changes: 1 addition & 1 deletion crates/shadowsocks-service/src/local/dns/client_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{
time::Duration,
};

use hickory_resolver::proto::{error::ProtoError, op::Message};
use hickory_resolver::proto::{op::Message, ProtoError};
use log::{debug, trace};
use tokio::sync::Mutex;

Expand Down
7 changes: 3 additions & 4 deletions crates/shadowsocks-service/src/local/dns/dns_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,11 @@ 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(Ipv4Addr::from(*addr).into(), port)),
Some(RData::AAAA(addr)) => vaddr.push(SocketAddr::new(Ipv6Addr::from(*addr).into(), port)),
Some(rdata) => {
RData::A(addr) => vaddr.push(SocketAddr::new(Ipv4Addr::from(*addr).into(), port)),
RData::AAAA(addr) => vaddr.push(SocketAddr::new(Ipv6Addr::from(*addr).into(), port)),
rdata => {
trace!("skipped rdata {:?}", rdata);
}
None => {}
}
}
vaddr
Expand Down
16 changes: 8 additions & 8 deletions crates/shadowsocks-service/src/local/dns/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ fn should_forward_by_response(
}
macro_rules! examine_record {
($rec:ident, $is_answer:expr) => {
if let Some(RData::CNAME(name)) = $rec.data() {
if let RData::CNAME(name) = $rec.data() {
if $is_answer {
if let Some(value) = check_name_in_proxy_list(acl, name) {
return value;
Expand All @@ -667,13 +667,13 @@ 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).into())),
Some(RData::AAAA(ip)) => acl.check_ip_in_proxy_list(&IpAddr::V6((*ip).into())),
RData::A(ip) => acl.check_ip_in_proxy_list(&IpAddr::V4((*ip).into())),
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),
RData::MX(mx) => examine_name!(mx.exchange(), $is_answer),
// NS records cause both the usual additional section processing to locate a type A record...
Some(RData::NS(name)) => examine_name!(name, $is_answer),
Some(RData::PTR(_)) => unreachable!(),
RData::NS(name) => examine_name!(name, $is_answer),
RData::PTR(_) => unreachable!(),
_ => acl.is_default_in_proxy_list(),
};
if !forward {
Expand Down Expand Up @@ -752,12 +752,12 @@ impl DnsClient {
for rec in result.answers() {
trace!("dns answer: {:?}", rec);
match rec.data() {
Some(RData::A(ip)) => {
RData::A(ip) => {
self.context
.add_to_reverse_lookup_cache(Ipv4Addr::from(*ip).into(), forward)
.await
}
Some(RData::AAAA(ip)) => {
RData::AAAA(ip) => {
self.context
.add_to_reverse_lookup_cache(Ipv6Addr::from(*ip).into(), forward)
.await
Expand Down
5 changes: 1 addition & 4 deletions crates/shadowsocks-service/src/local/dns/upstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ use std::{

use byteorder::{BigEndian, ByteOrder};
use bytes::{BufMut, BytesMut};
use hickory_resolver::proto::{
error::{ProtoError, ProtoErrorKind},
op::Message,
};
use hickory_resolver::proto::{op::Message, ProtoError, ProtoErrorKind};
use log::{error, trace};
use lru_time_cache::{Entry, LruCache};
use rand::{thread_rng, Rng};
Expand Down
29 changes: 18 additions & 11 deletions crates/shadowsocks-service/src/local/fake_dns/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use hickory_resolver::proto::{
DNSClass, RData, Record, RecordType,
},
};
use log::{debug, trace};
use log::{debug, trace, warn};

use super::manager::FakeDnsManager;

Expand All @@ -26,30 +26,37 @@ pub async fn handle_dns_request(req_message: &Message, manager: &FakeDnsManager)
rsp_message.add_query(query.clone());

if query.query_class() != DNSClass::IN {
let record = Record::<RData>::with(query.name().clone(), query.query_type(), 0);
rsp_message.add_answer(record);
// let record = Record::<RData>::from_rdata(query.name().clone(), 0, query.query_type());
// rsp_message.add_answer(record);
warn!(
"Query class: {:?} is not supported. Full {:?}",
query.query_class(),
req_message
);
continue;
}

match query.query_type() {
RecordType::A => {
let (ip_addr, expire_duration) = manager.map_domain_ipv4(query.name()).await?;
let [a, b, c, d] = ip_addr.octets();

let mut record =
Record::<RData>::with(query.name().clone(), RecordType::A, expire_duration.as_secs() as u32);
let mut record = Record::<RData>::from_rdata(
query.name().clone(),
expire_duration.as_secs() as u32,
RData::A(A(ip_addr)),
);
record.set_dns_class(query.query_class());
record.set_data(Some(RData::A(A::new(a, b, c, d))));
rsp_message.add_answer(record);
}
RecordType::AAAA => {
let (ip_addr, expire_duration) = manager.map_domain_ipv6(query.name()).await?;
let [a, b, c, d, e, f, g, h] = ip_addr.segments();

let mut record =
Record::<RData>::with(query.name().clone(), RecordType::AAAA, expire_duration.as_secs() as u32);
let mut record = Record::<RData>::from_rdata(
query.name().clone(),
expire_duration.as_secs() as u32,
RData::AAAA(AAAA(ip_addr)),
);
record.set_dns_class(query.query_class());
record.set_data(Some(RData::AAAA(AAAA::new(a, b, c, d, e, f, g, h))));
rsp_message.add_answer(record);
}
_ => {
Expand Down
2 changes: 1 addition & 1 deletion crates/shadowsocks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ tokio = { version = "1.9.0", features = [
"time",
] }

hickory-resolver = { version = "0.24", optional = true }
hickory-resolver = { version = "0.25.0-alpha", optional = true }
arc-swap = { version = "1.7", optional = true }
notify = { version = "7.0", optional = true }

Expand Down
50 changes: 31 additions & 19 deletions crates/shadowsocks/src/dns_resolver/hickory_dns_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,19 @@ use std::{
ops::Deref,
pin::Pin,
task::{Context, Poll},
time::Duration,
};

use cfg_if::cfg_if;
use futures::ready;
use hickory_resolver::{
config::{LookupIpStrategy, ResolverConfig, ResolverOpts},
error::ResolveResult,
name_server::{GenericConnector, RuntimeProvider},
name_server::GenericConnector,
proto::{
iocompat::AsyncIoTokioAsStd,
udp::{DnsUdpSocket, QuicLocalAddr},
TokioTime,
runtime::{iocompat::AsyncIoTokioAsStd, RuntimeProvider, TokioHandle, TokioTime},
udp::DnsUdpSocket,
},
AsyncResolver, TokioHandle,
ResolveError, Resolver,
};
use log::trace;
use tokio::{io::ReadBuf, net::UdpSocket};
Expand Down Expand Up @@ -62,12 +61,6 @@ impl DnsUdpSocket for ShadowUdpSocket {
}
}

impl QuicLocalAddr for ShadowUdpSocket {
fn local_addr(&self) -> io::Result<SocketAddr> {
self.deref().local_addr()
}
}

impl RuntimeProvider for ShadowDnsRuntimeProvider {
type Handle = TokioHandle;
type Tcp = AsyncIoTokioAsStd<ShadowTcpStream>;
Expand All @@ -78,10 +71,31 @@ impl RuntimeProvider for ShadowDnsRuntimeProvider {
self.handle.clone()
}

fn connect_tcp(&self, server_addr: SocketAddr) -> Pin<Box<dyn Send + Future<Output = io::Result<Self::Tcp>>>> {
let connect_opts = self.connect_opts.clone();
fn connect_tcp(
&self,
server_addr: SocketAddr,
bind_addr: Option<SocketAddr>,
wait_for: Option<Duration>,
) -> Pin<Box<dyn Send + Future<Output = io::Result<Self::Tcp>>>> {
let mut connect_opts = self.connect_opts.clone();

if let Some(bind_addr) = bind_addr {
connect_opts.bind_local_addr = Some(bind_addr.ip());
}

let wait_for = wait_for.unwrap_or_else(|| Duration::from_secs(5));

Box::pin(async move {
let tcp = ShadowTcpStream::connect_with_opts(&server_addr, &connect_opts).await?;
let tcp = match tokio::time::timeout(
wait_for,
ShadowTcpStream::connect_with_opts(&server_addr, &connect_opts),
)
.await
{
Ok(Ok(s)) => s,
Ok(Err(err)) => return Err(err),
Err(_) => return Err(io::ErrorKind::TimedOut.into()),
};
Ok(AsyncIoTokioAsStd(tcp))
})
}
Expand All @@ -105,14 +119,14 @@ pub type ShadowDnsConnectionProvider = GenericConnector<ShadowDnsRuntimeProvider
/// Shadowsocks DNS resolver
///
/// A customized hickory-dns-resolver
pub type DnsResolver = AsyncResolver<ShadowDnsConnectionProvider>;
pub type DnsResolver = Resolver<ShadowDnsConnectionProvider>;

/// Create a `hickory-dns` asynchronous DNS resolver
pub async fn create_resolver(
dns: Option<ResolverConfig>,
opts: Option<ResolverOpts>,
connect_opts: ConnectOpts,
) -> ResolveResult<DnsResolver> {
) -> Result<DnsResolver, ResolveError> {
// Customized dns resolution
match dns {
Some(conf) => {
Expand Down Expand Up @@ -173,8 +187,6 @@ pub async fn create_resolver(

Ok(DnsResolver::new(config, opts, ShadowDnsConnectionProvider::new(ShadowDnsRuntimeProvider::new(connect_opts))))
} else {
use hickory_resolver::error::ResolveError;

Err(ResolveError::from("current platform doesn't support hickory-dns resolver with system configured".to_owned()))
}
}
Expand Down

0 comments on commit a3ebc67

Please sign in to comment.