mirror of https://github.com/rapiz1/rathole.git
feat: cache dns result for one session (#166)
This commit is contained in:
parent
ee39a8e31e
commit
1f2fc5b28f
|
@ -6,7 +6,7 @@ use crate::protocol::{
|
||||||
self, read_ack, read_control_cmd, read_data_cmd, read_hello, Ack, Auth, ControlChannelCmd,
|
self, read_ack, read_control_cmd, read_data_cmd, read_hello, Ack, Auth, ControlChannelCmd,
|
||||||
DataChannelCmd, UdpTraffic, CURRENT_PROTO_VERSION, HASH_WIDTH_IN_BYTES,
|
DataChannelCmd, UdpTraffic, CURRENT_PROTO_VERSION, HASH_WIDTH_IN_BYTES,
|
||||||
};
|
};
|
||||||
use crate::transport::{SocketOpts, TcpTransport, Transport};
|
use crate::transport::{AddrMaybeCached, SocketOpts, TcpTransport, Transport};
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use backoff::ExponentialBackoff;
|
use backoff::ExponentialBackoff;
|
||||||
use backoff::{backoff::Backoff, future::retry_notify};
|
use backoff::{backoff::Backoff, future::retry_notify};
|
||||||
|
@ -150,7 +150,7 @@ impl<T: 'static + Transport> Client<T> {
|
||||||
|
|
||||||
struct RunDataChannelArgs<T: Transport> {
|
struct RunDataChannelArgs<T: Transport> {
|
||||||
session_key: Nonce,
|
session_key: Nonce,
|
||||||
remote_addr: String,
|
remote_addr: AddrMaybeCached,
|
||||||
connector: Arc<T>,
|
connector: Arc<T>,
|
||||||
socket_opts: SocketOpts,
|
socket_opts: SocketOpts,
|
||||||
service: ClientServiceConfig,
|
service: ClientServiceConfig,
|
||||||
|
@ -385,9 +385,12 @@ struct ControlChannelHandle {
|
||||||
impl<T: 'static + Transport> ControlChannel<T> {
|
impl<T: 'static + Transport> ControlChannel<T> {
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
async fn run(&mut self) -> Result<()> {
|
async fn run(&mut self) -> Result<()> {
|
||||||
|
let mut remote_addr = AddrMaybeCached::new(&self.remote_addr);
|
||||||
|
remote_addr.resolve().await?;
|
||||||
|
|
||||||
let mut conn = self
|
let mut conn = self
|
||||||
.transport
|
.transport
|
||||||
.connect(&self.remote_addr)
|
.connect(&remote_addr)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed to connect to {}", &self.remote_addr))?;
|
.with_context(|| format!("Failed to connect to {}", &self.remote_addr))?;
|
||||||
T::hint(&conn, SocketOpts::for_control_channel());
|
T::hint(&conn, SocketOpts::for_control_channel());
|
||||||
|
@ -432,7 +435,6 @@ impl<T: 'static + Transport> ControlChannel<T> {
|
||||||
// Channel ready
|
// Channel ready
|
||||||
info!("Control channel established");
|
info!("Control channel established");
|
||||||
|
|
||||||
let remote_addr = self.remote_addr.clone();
|
|
||||||
// Socket options for the data channel
|
// Socket options for the data channel
|
||||||
let socket_opts = SocketOpts::from_client_cfg(&self.service);
|
let socket_opts = SocketOpts::from_client_cfg(&self.service);
|
||||||
let data_ch_args = Arc::new(RunDataChannelArgs {
|
let data_ch_args = Arc::new(RunDataChannelArgs {
|
||||||
|
|
|
@ -10,6 +10,8 @@ use tokio::{
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::transport::AddrMaybeCached;
|
||||||
|
|
||||||
// Tokio hesitates to expose this option...So we have to do it on our own :(
|
// Tokio hesitates to expose this option...So we have to do it on our own :(
|
||||||
// The good news is that using socket2 it can be easily done, without losing portability.
|
// The good news is that using socket2 it can be easily done, without losing portability.
|
||||||
// See https://github.com/tokio-rs/tokio/issues/3082
|
// See https://github.com/tokio-rs/tokio/issues/3082
|
||||||
|
@ -40,7 +42,7 @@ pub fn feature_not_compile(feature: &str) -> ! {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn to_socket_addr<A: ToSocketAddrs>(addr: A) -> Result<SocketAddr> {
|
pub async fn to_socket_addr<A: ToSocketAddrs>(addr: A) -> Result<SocketAddr> {
|
||||||
lookup_host(addr)
|
lookup_host(addr)
|
||||||
.await?
|
.await?
|
||||||
.next()
|
.next()
|
||||||
|
@ -68,8 +70,12 @@ pub async fn udp_connect<A: ToSocketAddrs>(addr: A) -> Result<UdpSocket> {
|
||||||
|
|
||||||
/// Create a TcpStream using a proxy
|
/// Create a TcpStream using a proxy
|
||||||
/// e.g. socks5://user:pass@127.0.0.1:1080 http://127.0.0.1:8080
|
/// e.g. socks5://user:pass@127.0.0.1:1080 http://127.0.0.1:8080
|
||||||
pub async fn tcp_connect_with_proxy(addr: &str, proxy: Option<&Url>) -> Result<TcpStream> {
|
pub async fn tcp_connect_with_proxy(
|
||||||
|
addr: &AddrMaybeCached,
|
||||||
|
proxy: Option<&Url>,
|
||||||
|
) -> Result<TcpStream> {
|
||||||
if let Some(url) = proxy {
|
if let Some(url) = proxy {
|
||||||
|
let addr = &addr.addr;
|
||||||
let mut s = TcpStream::connect((
|
let mut s = TcpStream::connect((
|
||||||
url.host_str().expect("proxy url should have host field"),
|
url.host_str().expect("proxy url should have host field"),
|
||||||
url.port().expect("proxy url should have port field"),
|
url.port().expect("proxy url should have port field"),
|
||||||
|
@ -108,7 +114,10 @@ pub async fn tcp_connect_with_proxy(addr: &str, proxy: Option<&Url>) -> Result<T
|
||||||
}
|
}
|
||||||
Ok(s)
|
Ok(s)
|
||||||
} else {
|
} else {
|
||||||
Ok(TcpStream::connect(addr).await?)
|
Ok(match addr.socket_addr {
|
||||||
|
Some(s) => TcpStream::connect(s).await?,
|
||||||
|
None => TcpStream::connect(&addr.addr).await?,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::config::{ClientServiceConfig, ServerServiceConfig, TcpConfig, TransportConfig};
|
use crate::config::{ClientServiceConfig, ServerServiceConfig, TcpConfig, TransportConfig};
|
||||||
use crate::helper::try_set_tcp_keepalive;
|
use crate::helper::{to_socket_addr, try_set_tcp_keepalive};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::fmt::Debug;
|
use std::fmt::{Debug, Display};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::io::{AsyncRead, AsyncWrite};
|
use tokio::io::{AsyncRead, AsyncWrite};
|
||||||
|
@ -14,6 +14,40 @@ pub const DEFAULT_NODELAY: bool = false;
|
||||||
pub const DEFAULT_KEEPALIVE_SECS: u64 = 20;
|
pub const DEFAULT_KEEPALIVE_SECS: u64 = 20;
|
||||||
pub const DEFAULT_KEEPALIVE_INTERVAL: u64 = 8;
|
pub const DEFAULT_KEEPALIVE_INTERVAL: u64 = 8;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AddrMaybeCached {
|
||||||
|
pub addr: String,
|
||||||
|
pub socket_addr: Option<SocketAddr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddrMaybeCached {
|
||||||
|
pub fn new(addr: &str) -> AddrMaybeCached {
|
||||||
|
AddrMaybeCached {
|
||||||
|
addr: addr.to_string(),
|
||||||
|
socket_addr: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn resolve(&mut self) -> Result<()> {
|
||||||
|
match to_socket_addr(&self.addr).await {
|
||||||
|
Ok(s) => {
|
||||||
|
self.socket_addr = Some(s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AddrMaybeCached {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self.socket_addr {
|
||||||
|
Some(s) => f.write_fmt(format_args!("{}", s)),
|
||||||
|
None => f.write_str(&self.addr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Specify a transport layer, like TCP, TLS
|
/// Specify a transport layer, like TCP, TLS
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Transport: Debug + Send + Sync {
|
pub trait Transport: Debug + Send + Sync {
|
||||||
|
@ -30,7 +64,7 @@ pub trait Transport: Debug + Send + Sync {
|
||||||
/// accept must be cancel safe
|
/// accept must be cancel safe
|
||||||
async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)>;
|
async fn accept(&self, a: &Self::Acceptor) -> Result<(Self::RawStream, SocketAddr)>;
|
||||||
async fn handshake(&self, conn: Self::RawStream) -> Result<Self::Stream>;
|
async fn handshake(&self, conn: Self::RawStream) -> Result<Self::Stream>;
|
||||||
async fn connect(&self, addr: &str) -> Result<Self::Stream>;
|
async fn connect(&self, addr: &AddrMaybeCached) -> Result<Self::Stream>;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod tcp;
|
mod tcp;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use super::{SocketOpts, TcpTransport, Transport};
|
use super::{AddrMaybeCached, SocketOpts, TcpTransport, Transport};
|
||||||
use crate::config::{NoiseConfig, TransportConfig};
|
use crate::config::{NoiseConfig, TransportConfig};
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
@ -92,7 +92,7 @@ impl Transport for NoiseTransport {
|
||||||
Ok(conn)
|
Ok(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connect(&self, addr: &str) -> Result<Self::Stream> {
|
async fn connect(&self, addr: &AddrMaybeCached) -> Result<Self::Stream> {
|
||||||
let conn = self
|
let conn = self
|
||||||
.tcp
|
.tcp
|
||||||
.connect(addr)
|
.connect(addr)
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
helper::tcp_connect_with_proxy,
|
helper::tcp_connect_with_proxy,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{SocketOpts, Transport};
|
use super::{AddrMaybeCached, SocketOpts, Transport};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
@ -46,7 +46,7 @@ impl Transport for TcpTransport {
|
||||||
Ok(conn)
|
Ok(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connect(&self, addr: &str) -> Result<Self::Stream> {
|
async fn connect(&self, addr: &AddrMaybeCached) -> Result<Self::Stream> {
|
||||||
let s = tcp_connect_with_proxy(addr, self.cfg.proxy.as_ref()).await?;
|
let s = tcp_connect_with_proxy(addr, self.cfg.proxy.as_ref()).await?;
|
||||||
self.socket_opts.apply(&s);
|
self.socket_opts.apply(&s);
|
||||||
Ok(s)
|
Ok(s)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
use super::{SocketOpts, TcpTransport, Transport};
|
use super::{AddrMaybeCached, SocketOpts, TcpTransport, Transport};
|
||||||
use crate::config::{TlsConfig, TransportConfig};
|
use crate::config::{TlsConfig, TransportConfig};
|
||||||
use crate::helper::host_port_pair;
|
use crate::helper::host_port_pair;
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
|
@ -26,7 +26,10 @@ impl Transport for TlsTransport {
|
||||||
|
|
||||||
fn new(config: &TransportConfig) -> Result<Self> {
|
fn new(config: &TransportConfig) -> Result<Self> {
|
||||||
let tcp = TcpTransport::new(config)?;
|
let tcp = TcpTransport::new(config)?;
|
||||||
let config = config.tls.as_ref().ok_or_else(|| anyhow!("Missing tls config"))?;
|
let config = config
|
||||||
|
.tls
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| anyhow!("Missing tls config"))?;
|
||||||
|
|
||||||
let connector = match config.trusted_root.as_ref() {
|
let connector = match config.trusted_root.as_ref() {
|
||||||
Some(path) => {
|
Some(path) => {
|
||||||
|
@ -87,7 +90,7 @@ impl Transport for TlsTransport {
|
||||||
Ok(conn)
|
Ok(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connect(&self, addr: &str) -> Result<Self::Stream> {
|
async fn connect(&self, addr: &AddrMaybeCached) -> Result<Self::Stream> {
|
||||||
let conn = self.tcp.connect(addr).await?;
|
let conn = self.tcp.connect(addr).await?;
|
||||||
|
|
||||||
let connector = self.connector.as_ref().unwrap();
|
let connector = self.connector.as_ref().unwrap();
|
||||||
|
@ -96,7 +99,7 @@ impl Transport for TlsTransport {
|
||||||
self.config
|
self.config
|
||||||
.hostname
|
.hostname
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or(host_port_pair(addr)?.0),
|
.unwrap_or(host_port_pair(&addr.addr)?.0),
|
||||||
conn,
|
conn,
|
||||||
)
|
)
|
||||||
.await?)
|
.await?)
|
||||||
|
|
Loading…
Reference in New Issue