diff --git a/src/config.rs b/src/config.rs index c2956021..13a370c9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -124,6 +124,9 @@ pub struct ConfigBuilder { /// Close the connection if no substreams are open within this time frame. keep_alive_timeout: Duration, + + /// Use system's DNS config. + use_system_dns_config: bool, } impl Default for ConfigBuilder { @@ -157,6 +160,7 @@ impl ConfigBuilder { known_addresses: Vec::new(), connection_limits: ConnectionLimitsConfig::default(), keep_alive_timeout: KEEP_ALIVE_TIMEOUT, + use_system_dns_config: false, } } @@ -278,6 +282,12 @@ impl ConfigBuilder { self } + /// Set DNS resolver according to system configuration instead of default (Google). + pub fn with_system_resolver(mut self) -> Self { + self.use_system_dns_config = true; + self + } + /// Build [`Litep2pConfig`]. pub fn build(mut self) -> Litep2pConfig { let keypair = match self.keypair { @@ -307,6 +317,7 @@ impl ConfigBuilder { known_addresses: self.known_addresses, connection_limits: self.connection_limits, keep_alive_timeout: self.keep_alive_timeout, + use_system_dns_config: self.use_system_dns_config, } } } @@ -369,4 +380,7 @@ pub struct Litep2pConfig { /// Close the connection if no substreams are open within this time frame. pub(crate) keep_alive_timeout: Duration, + + /// Use system's DNS config. + pub(crate) use_system_dns_config: bool, } diff --git a/src/error.rs b/src/error.rs index 448005d0..c835c1c8 100644 --- a/src/error.rs +++ b/src/error.rs @@ -126,6 +126,8 @@ pub enum Error { ConnectionLimit(ConnectionLimitsError), #[error("Failed to dial peer immediately")] ImmediateDialError(#[from] ImmediateDialError), + #[error("Cannot read system DNS config: `{0}`")] + CannotReadSystemDnsConfig(hickory_resolver::ResolveError), } /// Error type for address parsing. diff --git a/src/lib.rs b/src/lib.rs index 32f61bf4..4951642e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,7 @@ use crate::transport::webrtc::WebRtcTransport; #[cfg(feature = "websocket")] use crate::transport::websocket::WebSocketTransport; +use hickory_resolver::{name_server::TokioConnectionProvider, TokioResolver}; use multiaddr::{Multiaddr, Protocol}; use multihash::Multihash; use transport::Endpoint; @@ -158,6 +159,18 @@ impl Litep2p { let bandwidth_sink = BandwidthSink::new(); let mut listen_addresses = vec![]; + let (resolver_config, resolver_opts) = if litep2p_config.use_system_dns_config { + hickory_resolver::system_conf::read_system_conf() + .map_err(Error::CannotReadSystemDnsConfig)? + } else { + (Default::default(), Default::default()) + }; + let resolver = Arc::new( + TokioResolver::builder_with_config(resolver_config, TokioConnectionProvider::default()) + .with_options(resolver_opts) + .build(), + ); + let supported_transports = Self::supported_transports(&litep2p_config); let (mut transport_manager, transport_handle) = TransportManager::new( litep2p_config.keypair.clone(), @@ -315,7 +328,7 @@ impl Litep2p { if let Some(config) = litep2p_config.tcp.take() { let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor)); let (transport, transport_listen_addresses) = - ::new(handle, config)?; + ::new(handle, config, resolver.clone())?; for address in transport_listen_addresses { transport_manager.register_listen_address(address.clone()); @@ -332,7 +345,7 @@ impl Litep2p { if let Some(config) = litep2p_config.quic.take() { let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor)); let (transport, transport_listen_addresses) = - ::new(handle, config)?; + ::new(handle, config, resolver.clone())?; for address in transport_listen_addresses { transport_manager.register_listen_address(address.clone()); @@ -349,7 +362,7 @@ impl Litep2p { if let Some(config) = litep2p_config.webrtc.take() { let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor)); let (transport, transport_listen_addresses) = - ::new(handle, config)?; + ::new(handle, config, resolver.clone())?; for address in transport_listen_addresses { transport_manager.register_listen_address(address.clone()); @@ -366,7 +379,7 @@ impl Litep2p { if let Some(config) = litep2p_config.websocket.take() { let handle = transport_manager.transport_handle(Arc::clone(&litep2p_config.executor)); let (transport, transport_listen_addresses) = - ::new(handle, config)?; + ::new(handle, config, resolver)?; for address in transport_listen_addresses { transport_manager.register_listen_address(address.clone()); diff --git a/src/transport/common/listener.rs b/src/transport/common/listener.rs index a79fe8ae..69be376f 100644 --- a/src/transport/common/listener.rs +++ b/src/transport/common/listener.rs @@ -26,9 +26,7 @@ use crate::{ }; use futures::Stream; -use hickory_resolver::{ - config::ResolverConfig, name_server::TokioConnectionProvider, TokioResolver, -}; +use hickory_resolver::TokioResolver; use multiaddr::{Multiaddr, Protocol}; use network_interface::{Addr, NetworkInterface, NetworkInterfaceConfig}; use socket2::{Domain, Socket, Type}; @@ -72,7 +70,7 @@ pub enum DnsType { impl AddressType { /// Resolve the address to a concrete IP. - pub async fn lookup_ip(self) -> Result { + pub async fn lookup_ip(self, resolver: Arc) -> Result { let (url, port, dns_type) = match self { // We already have the IP address. AddressType::Socket(address) => return Ok(address), @@ -83,12 +81,6 @@ impl AddressType { } => (address, port, dns_type), }; - let resolver = TokioResolver::builder_with_config( - ResolverConfig::default(), - TokioConnectionProvider::default(), - ) - .build(); - let lookup = match resolver.lookup_ip(url.clone()).await { Ok(lookup) => lookup, Err(error) => { diff --git a/src/transport/mod.rs b/src/transport/mod.rs index 1bf9b7d9..b293b8f2 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -23,9 +23,10 @@ use crate::{error::DialError, transport::manager::TransportHandle, types::ConnectionId, PeerId}; use futures::Stream; +use hickory_resolver::TokioResolver; use multiaddr::Multiaddr; -use std::{fmt::Debug, time::Duration}; +use std::{fmt::Debug, sync::Arc, time::Duration}; pub(crate) mod common; #[cfg(feature = "quic")] @@ -177,7 +178,11 @@ pub(crate) trait TransportBuilder { type Transport: Transport; /// Create new [`Transport`] object. - fn new(context: TransportHandle, config: Self::Config) -> crate::Result<(Self, Vec)> + fn new( + context: TransportHandle, + config: Self::Config, + resolver: Arc, + ) -> crate::Result<(Self, Vec)> where Self: Sized; } diff --git a/src/transport/quic/mod.rs b/src/transport/quic/mod.rs index 0cf5e255..2c153631 100644 --- a/src/transport/quic/mod.rs +++ b/src/transport/quic/mod.rs @@ -39,6 +39,7 @@ use futures::{ stream::{AbortHandle, FuturesUnordered}, Stream, StreamExt, TryFutureExt, }; +use hickory_resolver::TokioResolver; use multiaddr::{Multiaddr, Protocol}; use quinn::{ClientConfig, Connecting, Connection, Endpoint, IdleTimeout}; @@ -215,6 +216,7 @@ impl TransportBuilder for QuicTransport { fn new( context: TransportHandle, mut config: Self::Config, + _resolver: Arc, ) -> crate::Result<(Self, Vec)> where Self: Sized, @@ -621,9 +623,10 @@ mod tests { }, )]), }; + let resolver = Arc::new(TokioResolver::builder_tokio().unwrap().build()); let (mut transport1, listen_addresses) = - QuicTransport::new(handle1, Default::default()).unwrap(); + QuicTransport::new(handle1, Default::default(), resolver.clone()).unwrap(); let listen_address = listen_addresses[0].clone(); let keypair2 = Keypair::generate(); @@ -648,7 +651,8 @@ mod tests { )]), }; - let (mut transport2, _) = QuicTransport::new(handle2, Default::default()).unwrap(); + let (mut transport2, _) = + QuicTransport::new(handle2, Default::default(), resolver).unwrap(); let peer1: PeerId = PeerId::from_public_key(&keypair1.public().into()); let _peer2: PeerId = PeerId::from_public_key(&keypair2.public().into()); let listen_address = listen_address.with(Protocol::P2p( diff --git a/src/transport/tcp/connection.rs b/src/transport/tcp/connection.rs index c208af8d..c724dff6 100644 --- a/src/transport/tcp/connection.rs +++ b/src/transport/tcp/connection.rs @@ -752,6 +752,7 @@ mod tests { use crate::transport::tcp::TcpTransport; use super::*; + use hickory_resolver::{name_server::TokioConnectionProvider, TokioResolver}; use tokio::{io::AsyncWriteExt, net::TcpListener}; #[tokio::test] @@ -775,6 +776,13 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new( + TokioResolver::builder_with_config( + Default::default(), + TokioConnectionProvider::default(), + ) + .build(), + ), ) .await .unwrap(); @@ -870,6 +878,13 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new( + TokioResolver::builder_with_config( + Default::default(), + TokioConnectionProvider::default(), + ) + .build(), + ), ) .await .unwrap(); @@ -1012,6 +1027,13 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new( + TokioResolver::builder_with_config( + Default::default(), + TokioConnectionProvider::default(), + ) + .build(), + ), ) .await .unwrap(); @@ -1058,6 +1080,13 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new( + TokioResolver::builder_with_config( + Default::default(), + TokioConnectionProvider::default(), + ) + .build(), + ), ) .await .unwrap(); @@ -1231,6 +1260,13 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new( + TokioResolver::builder_with_config( + Default::default(), + TokioConnectionProvider::default(), + ) + .build(), + ), ) .await .unwrap(); @@ -1359,6 +1395,13 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new( + TokioResolver::builder_with_config( + Default::default(), + TokioConnectionProvider::default(), + ) + .build(), + ), ) .await .unwrap(); diff --git a/src/transport/tcp/mod.rs b/src/transport/tcp/mod.rs index 748e138d..a97fa417 100644 --- a/src/transport/tcp/mod.rs +++ b/src/transport/tcp/mod.rs @@ -42,6 +42,7 @@ use futures::{ stream::{AbortHandle, FuturesUnordered, Stream, StreamExt}, TryFutureExt, }; +use hickory_resolver::TokioResolver; use multiaddr::Multiaddr; use socket2::{Domain, Socket, Type}; use tokio::net::TcpStream; @@ -50,6 +51,7 @@ use std::{ collections::HashMap, net::SocketAddr, pin::Pin, + sync::Arc, task::{Context, Poll}, time::Duration, }; @@ -129,6 +131,9 @@ pub(crate) struct TcpTransport { /// Connections which have been opened and negotiated but are being validated by the /// `TransportManager`. pending_open: HashMap, + + /// DNS resolver. + resolver: Arc, } impl TcpTransport { @@ -176,11 +181,14 @@ impl TcpTransport { dial_addresses: DialAddresses, connection_open_timeout: Duration, nodelay: bool, + resolver: Arc, ) -> Result<(Multiaddr, TcpStream), DialError> { let (socket_address, _) = TcpAddress::multiaddr_to_socket_address(&address)?; let remote_address = - match tokio::time::timeout(connection_open_timeout, socket_address.lookup_ip()).await { + match tokio::time::timeout(connection_open_timeout, socket_address.lookup_ip(resolver)) + .await + { Err(_) => { tracing::debug!( target: LOG_TARGET, @@ -271,6 +279,7 @@ impl TransportBuilder for TcpTransport { fn new( context: TransportHandle, mut config: Self::Config, + resolver: Arc, ) -> crate::Result<(Self, Vec)> { tracing::debug!( target: LOG_TARGET, @@ -298,6 +307,7 @@ impl TransportBuilder for TcpTransport { pending_connections: FuturesStream::new(), pending_raw_connections: FuturesStream::new(), cancel_futures: HashMap::new(), + resolver, }, listen_addresses, )) @@ -317,13 +327,19 @@ impl Transport for TcpTransport { let dial_addresses = self.dial_addresses.clone(); let keypair = self.context.keypair.clone(); let nodelay = self.config.nodelay; + let resolver = self.resolver.clone(); self.pending_dials.insert(connection_id, address.clone()); self.pending_connections.push(Box::pin(async move { - let (_, stream) = - TcpTransport::dial_peer(address, dial_addresses, connection_open_timeout, nodelay) - .await - .map_err(|error| (connection_id, error))?; + let (_, stream) = TcpTransport::dial_peer( + address, + dial_addresses, + connection_open_timeout, + nodelay, + resolver, + ) + .await + .map_err(|error| (connection_id, error))?; TcpConnection::open_connection( connection_id, @@ -426,6 +442,7 @@ impl Transport for TcpTransport { let dial_addresses = self.dial_addresses.clone(); let connection_open_timeout = self.config.connection_open_timeout; let nodelay = self.config.nodelay; + let resolver = self.resolver.clone(); async move { TcpTransport::dial_peer( @@ -433,6 +450,7 @@ impl Transport for TcpTransport { dial_addresses, connection_open_timeout, nodelay, + resolver, ) .await .map_err(|error| (address, error)) @@ -727,9 +745,10 @@ mod tests { listen_addresses: vec!["/ip6/::1/tcp/0".parse().unwrap()], ..Default::default() }; + let resolver = Arc::new(TokioResolver::builder_tokio().unwrap().build()); let (mut transport1, listen_addresses) = - TcpTransport::new(handle1, transport_config1).unwrap(); + TcpTransport::new(handle1, transport_config1, resolver.clone()).unwrap(); let listen_address = listen_addresses[0].clone(); let keypair2 = Keypair::generate(); @@ -758,7 +777,7 @@ mod tests { ..Default::default() }; - let (mut transport2, _) = TcpTransport::new(handle2, transport_config2).unwrap(); + let (mut transport2, _) = TcpTransport::new(handle2, transport_config2, resolver).unwrap(); transport2.dial(ConnectionId::new(), listen_address).unwrap(); let (tx, mut from_transport2) = channel(64); @@ -820,9 +839,10 @@ mod tests { listen_addresses: vec!["/ip6/::1/tcp/0".parse().unwrap()], ..Default::default() }; + let resolver = Arc::new(TokioResolver::builder_tokio().unwrap().build()); let (mut transport1, listen_addresses) = - TcpTransport::new(handle1, transport_config1).unwrap(); + TcpTransport::new(handle1, transport_config1, resolver.clone()).unwrap(); let listen_address = listen_addresses[0].clone(); let keypair2 = Keypair::generate(); @@ -851,7 +871,7 @@ mod tests { ..Default::default() }; - let (mut transport2, _) = TcpTransport::new(handle2, transport_config2).unwrap(); + let (mut transport2, _) = TcpTransport::new(handle2, transport_config2, resolver).unwrap(); transport2.dial(ConnectionId::new(), listen_address).unwrap(); let (tx, mut from_transport2) = channel(64); @@ -904,7 +924,9 @@ mod tests { }, )]), }; - let (mut transport1, _) = TcpTransport::new(handle1, Default::default()).unwrap(); + let resolver = Arc::new(TokioResolver::builder_tokio().unwrap().build()); + let (mut transport1, _) = + TcpTransport::new(handle1, Default::default(), resolver.clone()).unwrap(); tokio::spawn(async move { while let Some(event) = transport1.next().await { @@ -941,7 +963,7 @@ mod tests { )]), }; - let (mut transport2, _) = TcpTransport::new(handle2, Default::default()).unwrap(); + let (mut transport2, _) = TcpTransport::new(handle2, Default::default(), resolver).unwrap(); let peer1: PeerId = PeerId::from_public_key(&keypair1.public().into()); let peer2: PeerId = PeerId::from_public_key(&keypair2.public().into()); @@ -982,6 +1004,7 @@ mod tests { ConnectionLimitsConfig::default(), ); let handle = manager.transport_handle(Arc::new(DefaultExecutor {})); + let resolver = Arc::new(TokioResolver::builder_tokio().unwrap().build()); manager.register_transport( SupportedTransport::Tcp, Box::new(crate::transport::dummy::DummyTransport::new()), @@ -992,6 +1015,7 @@ mod tests { listen_addresses: vec!["/ip4/127.0.0.1/tcp/0".parse().unwrap()], ..Default::default() }, + resolver, ) .unwrap(); diff --git a/src/transport/webrtc/mod.rs b/src/transport/webrtc/mod.rs index 7dce743d..bc060102 100644 --- a/src/transport/webrtc/mod.rs +++ b/src/transport/webrtc/mod.rs @@ -33,6 +33,7 @@ use crate::{ use futures::{future::BoxFuture, Future, Stream}; use futures_timer::Delay; +use hickory_resolver::TokioResolver; use multiaddr::{multihash::Multihash, Multiaddr, Protocol}; use socket2::{Domain, Socket, Type}; use str0m::{ @@ -423,7 +424,11 @@ impl TransportBuilder for WebRtcTransport { type Transport = WebRtcTransport; /// Create new [`Transport`] object. - fn new(context: TransportHandle, config: Self::Config) -> crate::Result<(Self, Vec)> + fn new( + context: TransportHandle, + config: Self::Config, + _resolver: Arc, + ) -> crate::Result<(Self, Vec)> where Self: Sized, { diff --git a/src/transport/websocket/connection.rs b/src/transport/websocket/connection.rs index d6dc9268..dcfe60e0 100644 --- a/src/transport/websocket/connection.rs +++ b/src/transport/websocket/connection.rs @@ -606,6 +606,8 @@ mod tests { use super::*; use futures::AsyncWriteExt; + use hickory_resolver::TokioResolver; + use std::sync::Arc; use tokio::net::TcpListener; #[tokio::test] @@ -639,6 +641,7 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new(TokioResolver::builder_tokio().unwrap().build()), ) .await .unwrap(); @@ -754,6 +757,7 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new(TokioResolver::builder_tokio().unwrap().build()), ) .await .unwrap(); @@ -1025,6 +1029,7 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new(TokioResolver::builder_tokio().unwrap().build()), ) .await .unwrap(); @@ -1192,6 +1197,7 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new(TokioResolver::builder_tokio().unwrap().build()), ) .await .unwrap(); @@ -1345,6 +1351,7 @@ mod tests { Default::default(), Duration::from_secs(10), false, + Arc::new(TokioResolver::builder_tokio().unwrap().build()), ) .await .unwrap(); diff --git a/src/transport/websocket/mod.rs b/src/transport/websocket/mod.rs index 72bb0305..11013e6c 100644 --- a/src/transport/websocket/mod.rs +++ b/src/transport/websocket/mod.rs @@ -42,9 +42,10 @@ use futures::{ stream::{AbortHandle, FuturesUnordered}, Stream, StreamExt, TryFutureExt, }; +use hickory_resolver::TokioResolver; use multiaddr::{Multiaddr, Protocol}; use socket2::{Domain, Socket, Type}; -use std::net::SocketAddr; +use std::{net::SocketAddr, sync::Arc}; use tokio::net::TcpStream; use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; @@ -132,6 +133,9 @@ pub(crate) struct WebSocketTransport { /// Negotiated connections waiting validation. pending_open: HashMap, + + /// DNS resolver. + resolver: Arc, } impl WebSocketTransport { @@ -224,12 +228,15 @@ impl WebSocketTransport { dial_addresses: DialAddresses, connection_open_timeout: Duration, nodelay: bool, + resolver: Arc, ) -> Result<(Multiaddr, WebSocketStream>), DialError> { let (url, _) = Self::multiaddr_into_url(address.clone())?; let (socket_address, _) = WebSocketAddress::multiaddr_to_socket_address(&address)?; let remote_address = - match tokio::time::timeout(connection_open_timeout, socket_address.lookup_ip()).await { + match tokio::time::timeout(connection_open_timeout, socket_address.lookup_ip(resolver)) + .await + { Err(_) => return Err(DialError::Timeout), Ok(Err(error)) => return Err(error.into()), Ok(Ok(address)) => address, @@ -302,6 +309,7 @@ impl TransportBuilder for WebSocketTransport { fn new( context: TransportHandle, mut config: Self::Config, + resolver: Arc, ) -> crate::Result<(Self, Vec)> where Self: Sized, @@ -330,6 +338,7 @@ impl TransportBuilder for WebSocketTransport { pending_connections: FuturesStream::new(), pending_raw_connections: FuturesStream::new(), cancel_futures: HashMap::new(), + resolver, }, listen_addresses, )) @@ -347,6 +356,7 @@ impl Transport for WebSocketTransport { let substream_open_timeout = self.config.substream_open_timeout; let dial_addresses = self.dial_addresses.clone(); let nodelay = self.config.nodelay; + let resolver = self.resolver.clone(); self.pending_dials.insert(connection_id, address.clone()); @@ -358,6 +368,7 @@ impl Transport for WebSocketTransport { dial_addresses, connection_open_timeout, nodelay, + resolver, ) .await .map_err(|error| (connection_id, error))?; @@ -475,6 +486,7 @@ impl Transport for WebSocketTransport { let connection_open_timeout = self.config.connection_open_timeout; let dial_addresses = self.dial_addresses.clone(); let nodelay = self.config.nodelay; + let resolver = self.resolver.clone(); async move { WebSocketTransport::dial_peer( @@ -482,6 +494,7 @@ impl Transport for WebSocketTransport { dial_addresses, connection_open_timeout, nodelay, + resolver, ) .await .map_err(|error| (address, error))