Skip to content

Commit

Permalink
fix(smol): DNS resolution result compatible with IP version
Browse files Browse the repository at this point in the history
  • Loading branch information
XOR-op committed Sep 16, 2024
1 parent a25e814 commit a3a8e28
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 6 deletions.
7 changes: 6 additions & 1 deletion boltconn/src/dispatch/dispatching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -855,11 +855,16 @@ impl DispatchingSnippet {
}
if verbose {
tracing::info!(
"[{}]({},{}) {} => {}",
"[{}]({},{}) {}{} => {}",
rule_str,
stringfy_process(info),
info.inbound,
info.dst,
if info.connection_type == NetworkType::Udp {
"(UDP)"
} else {
""
},
proxy,
);
}
Expand Down
18 changes: 15 additions & 3 deletions boltconn/src/network/dns/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,23 @@ impl<P: RuntimeProvider> GenericDns<P> {
}

pub async fn genuine_lookup(&self, domain_name: &str) -> Option<IpAddr> {
self.genuine_lookup_with(domain_name, self.preference).await
}

pub async fn genuine_lookup_with(
&self,
domain_name: &str,
pref: DnsPreference,
) -> Option<IpAddr> {
if let Some(ip) = self.host_resolver.load().resolve(domain_name) {
return Some(ip);
if (matches!(pref, DnsPreference::Ipv6Only) && ip.is_ipv6())
|| (matches!(pref, DnsPreference::Ipv4Only) && ip.is_ipv4())
{
return Some(ip);
}
}
if let Some(resolver) = self.ns_policy.load().resolve(domain_name) {
return match self.preference {
return match pref {
DnsPreference::Ipv4Only => Self::one_v4_wrapper(domain_name, resolver).await,
DnsPreference::Ipv6Only => Self::one_v6_wrapper(domain_name, resolver).await,
DnsPreference::PreferIpv4 => {
Expand All @@ -207,7 +219,7 @@ impl<P: RuntimeProvider> GenericDns<P> {
}
};
}
match self.preference {
match pref {
DnsPreference::Ipv4Only => self.genuine_lookup_v4(domain_name).await,
DnsPreference::Ipv6Only => self.genuine_lookup_v6(domain_name).await,
DnsPreference::PreferIpv4 => {
Expand Down
52 changes: 50 additions & 2 deletions boltconn/src/transport/smol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::adapter::{AddrConnector, AddrConnectorWrapper, Connector};

use crate::common::duplex_chan::DuplexChan;
use crate::common::{mut_buf, MAX_PKT_SIZE};
use crate::config::DnsPreference;
use crate::network::dns::GenericDns;
use crate::proxy::{ConnAbortHandle, NetworkAddr};
use crate::transport::InterfaceAddress;
Expand Down Expand Up @@ -240,12 +241,28 @@ impl Drop for TcpConnTask {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
enum IPVersion {
V4,
V6,
}

impl IPVersion {
pub fn from_addr(addr: &IpAddr) -> Self {
match addr {
IpAddr::V4(_) => Self::V4,
IpAddr::V6(_) => Self::V6,
}
}
}

struct UdpConnTask {
back_tx: mpsc::Sender<(Bytes, NetworkAddr)>,
rx: flume::Receiver<(Bytes, SocketAddr)>,
handle: SocketHandle,
abort_handle: ConnAbortHandle,
last_active: Instant,
socket_version: IPVersion,
}

impl UdpConnTask {
Expand All @@ -255,6 +272,7 @@ impl UdpConnTask {
abort_handle: ConnAbortHandle,
dns: Arc<GenericDns<SmolDnsProvider>>,
notify: Arc<Notify>,
socket_version: IPVersion,
) -> Self {
let AddrConnector {
tx: back_tx,
Expand All @@ -264,9 +282,28 @@ impl UdpConnTask {
tokio::spawn(async move {
while let Some((buf, dst)) = back_rx.recv().await {
if let Some(dst) = match dst {
NetworkAddr::Raw(s) => Some(s),
NetworkAddr::Raw(s) => {
if (s.is_ipv4() && socket_version == IPVersion::V4)
|| (s.is_ipv6() && socket_version == IPVersion::V6)
{
Some(s)
} else {
tracing::warn!(
"smol: {} sent from mismatched IP version: {:?}",
s,
socket_version
);
None
}
}
NetworkAddr::DomainName { domain_name, port } => dns
.genuine_lookup(domain_name.as_str())
.genuine_lookup_with(
domain_name.as_str(),
match socket_version {
IPVersion::V4 => DnsPreference::Ipv4Only,
IPVersion::V6 => DnsPreference::Ipv6Only,
},
)
.await
.map(|ip| SocketAddr::new(ip, port)),
} {
Expand All @@ -281,6 +318,7 @@ impl UdpConnTask {
handle,
abort_handle,
last_active: Instant::now(),
socket_version,
}
}

Expand All @@ -293,6 +331,14 @@ impl UdpConnTask {
// todo: full-cone NAT
Ok((buf, addr)) => {
has_activity = true;
if IPVersion::from_addr(&addr.ip()) != self.socket_version {
tracing::warn!(
"smol: {} sent from mismatched IP version: {:?}",
addr,
self.socket_version
);
continue;
}
if socket
.send_slice(buf.as_ref(), IpEndpoint::from(addr))
.is_ok()
Expand Down Expand Up @@ -518,6 +564,7 @@ impl SmolStack {
abort_handle,
self.dns.clone(),
notify,
IPVersion::from_addr(&local_addr.ip()),
));
return Ok(());
}
Expand All @@ -542,6 +589,7 @@ impl SmolStack {
abort_handle,
self.dns.clone(),
notify,
IPVersion::from_addr(&local_addr.ip()),
));
Ok(())
}
Expand Down

0 comments on commit a3a8e28

Please sign in to comment.