net: fix domain resolving for datagram outbound address

This commit is contained in:
eric
2024-04-18 16:38:10 +08:00
parent 4d7908229b
commit 190727f325
3 changed files with 78 additions and 10 deletions

View File

@@ -7,7 +7,7 @@ use cidr::IpCidr;
use futures::TryFutureExt;
use maxminddb::geoip2::Country;
use maxminddb::Mmap;
use tracing::{debug, trace, warn};
use tracing::{debug, warn};
use crate::app::SyncDnsClient;
use crate::config;

View File

@@ -68,6 +68,78 @@ impl OutboundDatagramSendHalf for StdOutboundDatagramSendHalf {
}
}
pub struct DomainResolveOutboundDatagram {
inner: UdpSocket,
dns_client: SyncDnsClient,
}
impl DomainResolveOutboundDatagram {
pub fn new(inner: UdpSocket, dns_client: SyncDnsClient) -> Self {
Self { inner, dns_client }
}
}
impl OutboundDatagram for DomainResolveOutboundDatagram {
fn split(
self: Box<Self>,
) -> (
Box<dyn OutboundDatagramRecvHalf>,
Box<dyn OutboundDatagramSendHalf>,
) {
let r = Arc::new(self.inner);
let s = r.clone();
(
Box::new(DomainResolveOutboundDatagramRecvHalf(r)),
Box::new(DomainResolveOutboundDatagramSendHalf(s, self.dns_client)),
)
}
}
pub struct DomainResolveOutboundDatagramRecvHalf(Arc<UdpSocket>);
#[async_trait]
impl OutboundDatagramRecvHalf for DomainResolveOutboundDatagramRecvHalf {
async fn recv_from(&mut self, buf: &mut [u8]) -> io::Result<(usize, SocksAddr)> {
match self.0.recv_from(buf).await {
Ok((n, a)) => Ok((n, SocksAddr::Ip(unmapped_ipv4(a)))),
Err(e) => Err(e),
}
}
}
pub struct DomainResolveOutboundDatagramSendHalf(Arc<UdpSocket>, SyncDnsClient);
#[async_trait]
impl OutboundDatagramSendHalf for DomainResolveOutboundDatagramSendHalf {
async fn send_to(&mut self, buf: &[u8], target: &SocksAddr) -> io::Result<usize> {
match target {
SocksAddr::Domain(domain, port) => {
let ips = self
.1
.read()
.await
.direct_lookup(domain)
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("lookup {} failed: {}", domain, e),
)
})
.await?;
let ip = ips
.first()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "no results"))?;
self.0.send_to(buf, SocketAddr::new(*ip, *port)).await
}
SocksAddr::Ip(addr) => self.0.send_to(buf, addr).await,
}
}
async fn close(&mut self) -> io::Result<()> {
Ok(())
}
}
/// An outbound datagram that sends to a domain target.
pub struct DomainAssociatedOutboundDatagram {
inner: UdpSocket,
@@ -133,7 +205,7 @@ pub struct DomainAssociatedOutboundDatagramRecvHalf(Arc<UdpSocket>, SocksAddr);
impl OutboundDatagramRecvHalf for DomainAssociatedOutboundDatagramRecvHalf {
async fn recv_from(&mut self, buf: &mut [u8]) -> io::Result<(usize, SocksAddr)> {
match self.0.recv_from(buf).await {
Ok((n, a)) => Ok((n, self.1.clone())),
Ok((n, _a)) => Ok((n, self.1.clone())),
Err(e) => Err(e),
}
}
@@ -150,7 +222,7 @@ impl OutboundDatagramSendHalf for DomainAssociatedOutboundDatagramSendHalf {
self.2
.read()
.await
.lookup(domain)
.direct_lookup(domain)
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,

View File

@@ -13,7 +13,7 @@ use thiserror::Error;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::{TcpSocket, TcpStream, UdpSocket};
use tokio::time::timeout;
use tracing::{debug, trace};
use tracing::debug;
#[cfg(unix)]
use std::os::unix::io::{AsFd, AsRawFd};
@@ -83,11 +83,7 @@ pub mod vmess;
#[cfg(any(feature = "inbound-ws", feature = "outbound-ws"))]
pub mod ws;
pub use datagram::{
DomainAssociatedOutboundDatagram, DomainAssociatedOutboundDatagramRecvHalf,
DomainAssociatedOutboundDatagramSendHalf, SimpleInboundDatagram, SimpleInboundDatagramRecvHalf,
SimpleInboundDatagramSendHalf, StdOutboundDatagram,
};
pub use datagram::*;
#[derive(Error, Debug)]
pub enum ProxyError {
@@ -411,7 +407,7 @@ pub async fn connect_datagram_outbound(
Network::Udp => {
let socket = new_udp_socket(&sess.source).await?;
Ok(Some(OutboundTransport::Datagram(Box::new(
StdOutboundDatagram::new(socket),
DomainResolveOutboundDatagram::new(socket, dns_client.clone()),
))))
}
Network::Tcp => {