131 lines
4.0 KiB
Rust
131 lines
4.0 KiB
Rust
#[cfg(all(
|
|
any(feature = "webpki-roots", feature = "rustls-platform-verifier"),
|
|
feature = "__https"
|
|
))]
|
|
use hickory_resolver::config::CLOUDFLARE;
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
use {
|
|
hickory_resolver::{
|
|
ConnectionProvider, Resolver,
|
|
config::{GOOGLE, ResolverConfig},
|
|
net::runtime::{RuntimeProvider, TokioHandle, TokioTime, iocompat::AsyncIoTokioAsStd},
|
|
},
|
|
std::future::Future,
|
|
std::io,
|
|
std::net::SocketAddr,
|
|
std::pin::Pin,
|
|
std::time::Duration,
|
|
tokio::net::{TcpSocket, TcpStream, UdpSocket},
|
|
tokio::time::timeout,
|
|
};
|
|
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
#[derive(Clone, Default)]
|
|
struct PrintProvider {
|
|
handle: TokioHandle,
|
|
}
|
|
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
impl RuntimeProvider for PrintProvider {
|
|
type Handle = TokioHandle;
|
|
type Timer = TokioTime;
|
|
type Udp = UdpSocket;
|
|
type Tcp = AsyncIoTokioAsStd<TcpStream>;
|
|
|
|
fn create_handle(&self) -> Self::Handle {
|
|
self.handle.clone()
|
|
}
|
|
|
|
fn connect_tcp(
|
|
&self,
|
|
server_addr: SocketAddr,
|
|
bind_addr: Option<SocketAddr>,
|
|
wait_for: Option<Duration>,
|
|
) -> Pin<Box<dyn Send + Future<Output = Result<Self::Tcp, io::Error>>>> {
|
|
Box::pin(async move {
|
|
let socket = match server_addr {
|
|
SocketAddr::V4(_) => TcpSocket::new_v4(),
|
|
SocketAddr::V6(_) => TcpSocket::new_v6(),
|
|
}?;
|
|
|
|
if let Some(bind_addr) = bind_addr {
|
|
socket.bind(bind_addr)?;
|
|
}
|
|
|
|
socket.set_nodelay(true)?;
|
|
let future = socket.connect(server_addr);
|
|
let wait_for = wait_for.unwrap_or_else(|| Duration::from_secs(5));
|
|
match timeout(wait_for, future).await {
|
|
Ok(Ok(socket)) => Ok(AsyncIoTokioAsStd(socket)),
|
|
Ok(Err(e)) => Err(e),
|
|
Err(_) => Err(io::Error::new(
|
|
io::ErrorKind::TimedOut,
|
|
"TCP connect timed out",
|
|
)),
|
|
}
|
|
})
|
|
}
|
|
|
|
fn bind_udp(
|
|
&self,
|
|
local_addr: SocketAddr,
|
|
server_addr: SocketAddr,
|
|
) -> Pin<Box<dyn Send + Future<Output = Result<Self::Udp, io::Error>>>> {
|
|
// The server_addr parameter is used only when you need to establish a tunnel or something similar.
|
|
// For example, you try to use a http proxy and encapsulate UDP packets inside a TCP stream.
|
|
println!("Create udp local_addr: {local_addr}, server_addr: {server_addr}");
|
|
Box::pin(async move { UdpSocket::bind(local_addr).await })
|
|
}
|
|
}
|
|
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
async fn lookup_test<R: ConnectionProvider>(resolver: Resolver<R>) {
|
|
let response = resolver.lookup_ip("www.example.com.").await.unwrap();
|
|
|
|
assert_ne!(response.iter().count(), 0, "no addresses returned!");
|
|
}
|
|
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
#[tokio::main]
|
|
async fn main() {
|
|
tracing_subscriber::fmt::init();
|
|
run().await;
|
|
}
|
|
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
async fn run() {
|
|
let resolver = Resolver::builder_with_config(
|
|
ResolverConfig::udp_and_tcp(&GOOGLE),
|
|
PrintProvider::default(),
|
|
)
|
|
.build()
|
|
.unwrap();
|
|
|
|
lookup_test(resolver).await;
|
|
|
|
#[cfg(feature = "__https")]
|
|
{
|
|
let resolver2 = Resolver::builder_with_config(
|
|
ResolverConfig::https(&CLOUDFLARE),
|
|
PrintProvider::default(),
|
|
)
|
|
.build()
|
|
.unwrap();
|
|
lookup_test(resolver2).await;
|
|
}
|
|
|
|
println!("Hello, world!");
|
|
}
|
|
|
|
#[cfg(not(any(feature = "webpki-roots", feature = "rustls-platform-verifier")))]
|
|
fn main() {
|
|
println!("either `webpki-roots` or `rustls-platform-verifier` feature must be enabled")
|
|
}
|
|
|
|
#[cfg(any(feature = "webpki-roots", feature = "rustls-platform-verifier"))]
|
|
#[tokio::test]
|
|
async fn test_custom_provider() {
|
|
test_support::subscribe();
|
|
run().await;
|
|
}
|