Skip to main content

hickory_resolver/
lib.rs

1// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! The Resolver is responsible for performing recursive queries to lookup domain names.
9//!
10//! This is a 100% in process DNS resolver. It *does not* use the Host OS' resolver. If what is
11//! desired is to use the Host OS' resolver, generally in the system's libc, then the
12//! `std::net::ToSocketAddrs` variant over `&str` should be used.
13//!
14//! Unlike the `hickory-client`, this tries to provide a simpler interface to perform DNS
15//! queries. For update options, i.e. Dynamic DNS, the `hickory-client` crate must be used
16//! instead. The Resolver library is capable of searching multiple domains (this can be disabled by
17//! using an FQDN during lookup), dual-stack IPv4/IPv6 lookups, performing chained CNAME lookups,
18//! and features connection metric tracking for attempting to pick the best upstream DNS resolver.
19//!
20//! This as best as possible attempts to abide by the DNS RFCs, please file issues at
21//! <https://github.com/hickory-dns/hickory-dns>.
22//!
23//! # Usage
24//!
25//! ## Declare dependency
26//!
27//! ```toml
28//! [dependency]
29//! hickory-resolver = "*"
30//! ```
31//!
32//! ## Using the host system config
33//!
34//! On Unix systems, the `/etc/resolv.conf` can be used for configuration. Not all options
35//! specified in the host systems `resolv.conf` are applicable or compatible with this software. In
36//! addition there may be additional options supported which the host system does not. Example:
37//!
38//! ```rust,no_run
39//! # fn main() {
40//! # #[cfg(all(unix, feature = "tokio", feature = "system-config"))]
41//! # {
42//! # use std::net::*;
43//! # use tokio::runtime::Runtime;
44//! # Runtime::new().unwrap().block_on(async {
45//! use hickory_resolver::Resolver;
46//! // Use the host OS'es `/etc/resolv.conf`
47//! # #[cfg(unix)]
48//! let resolver = Resolver::builder_tokio().unwrap().build().unwrap();
49//! # #[cfg(unix)]
50//! let response = resolver.lookup_ip("www.example.com.").await.unwrap();
51//! # })
52//! # }
53//! # }
54//! ```
55//!
56//! ## Using the Tokio/Async Resolver
57//!
58//! ```rust
59//! # fn main() {
60//! # #[cfg(feature = "tokio")]
61//! # {
62//! use std::net::*;
63//! use tokio::runtime::Runtime;
64//! use hickory_resolver::Resolver;
65//! use hickory_resolver::net::runtime::TokioRuntimeProvider;
66//! use hickory_resolver::config::*;
67//!
68//! // We need a Tokio Runtime to run the resolver
69//! //  this is responsible for running all Future tasks and registering interest in IO channels
70//! let mut io_loop = Runtime::new().unwrap();
71//!
72//! // Construct a new Resolver with default configuration options
73//! let resolver = Resolver::builder_with_config(
74//!     ResolverConfig::udp_and_tcp(&GOOGLE),
75//!     TokioRuntimeProvider::default()
76//! ).build().unwrap();
77//!
78//! // Lookup the IP addresses associated with a name.
79//! // This returns a future that will lookup the IP addresses, it must be run in the Core to
80//! //  to get the actual result.
81//! let lookup_future = resolver.lookup_ip("www.example.com.");
82//!
83//! // Run the lookup until it resolves or errors
84//! let mut response = io_loop.block_on(lookup_future).unwrap();
85//!
86//! // There can be many addresses associated with the name,
87//! //  this can return IPv4 and/or IPv6 addresses
88//! let _address = response.iter().next().expect("no addresses returned!");
89//! # }
90//! # }
91//! ```
92//!
93//! Generally after a lookup in an asynchronous context, there would probably be a connection made
94//! to a server, for example:
95//!
96//! ```rust,no_run
97//! # fn main() {
98//! # #[cfg(feature = "tokio")]
99//! # {
100//! # use std::net::TcpStream;
101//! # use tokio::runtime::Runtime;
102//! # use hickory_resolver::Resolver;
103//! # use hickory_resolver::net::runtime::TokioRuntimeProvider;
104//! # use hickory_resolver::config::ResolverConfig;
105//! #
106//! # let mut io_loop = Runtime::new().unwrap();
107//! #
108//! # let resolver = Resolver::builder_with_config(
109//! #     ResolverConfig::default(),
110//! #     TokioRuntimeProvider::default()
111//! # ).build().unwrap();
112//! # io_loop.block_on(async {
113//! let ips = resolver.lookup_ip("www.example.com.").await.unwrap();
114//!
115//! let ip = ips.iter().next().unwrap();
116//! let conn = TcpStream::connect((ip, 443)).unwrap();
117//! /* do something with the connection... */
118//! # });
119//! # }
120//! # }
121//! ```
122//!
123//! It's beyond the scope of these examples to show how to deal with connection failures and
124//! looping etc. But if you wanted to say try a different address from the result set after a
125//! connection failure, it will be necessary to create a type that implements the `Future` trait.
126//! Inside the `Future::poll` method would be the place to implement a loop over the different IP
127//! addresses.
128//!
129//! ## Optional protocol support
130//!
131//! The following DNS protocols are optionally supported:
132//!
133//! - Enable `tls` for DNS over TLS (DoT)
134//! - Enable `https-rustls` for DNS over HTTP/2 (DoH)
135//! - Enable `quic` for DNS over QUIC (DoQ)
136//! - Enable `h3` for DNS over HTTP/3 (DoH3)
137//!
138//! ### Example
139//!
140//! Enable the TLS library through the dependency on `hickory-resolver`:
141//!
142//! ```toml
143//! hickory-resolver = { version = "*", features = ["tls"] }
144//! ```
145//!
146//! A default TLS configuration is available for Cloudflare's `1.1.1.1` DNS service (Quad9 as
147//! well):
148//!
149//! ```rust,no_run
150//! # fn main() {
151//! # #[cfg(feature = "tokio")]
152//! # {
153//! use hickory_resolver::Resolver;
154//! use hickory_resolver::net::runtime::TokioRuntimeProvider;
155//! use hickory_resolver::config::*;
156//!
157//! // Construct a new Resolver with default configuration options
158//! # #[cfg(feature = "__tls")]
159//! let mut resolver = Resolver::builder_with_config(
160//!     ResolverConfig::tls(&CLOUDFLARE),
161//!     TokioRuntimeProvider::default(),
162//! ).build();
163//!
164//! // see example above...
165//! # }
166//! # }
167//! ```
168//!
169//! ## mDNS (multicast DNS)
170//!
171//! Multicast DNS is an experimental feature in Hickory DNS at the moment. Its support on different
172//! platforms is not yet ideal. Initial support is only for IPv4 mDNS, as there are some
173//! complexities to figure out with IPv6. Once enabled, an mDNS `NameServer` will automatically be
174//! added to the `Resolver` and used for any lookups performed in the `.local.` zone.
175
176#![warn(clippy::dbg_macro, clippy::print_stdout, missing_docs)]
177#![cfg_attr(docsrs, feature(doc_cfg))]
178
179pub use hickory_net as net;
180pub use hickory_proto as proto;
181
182pub mod caching_client;
183pub mod config;
184mod connection_provider;
185pub use connection_provider::{ConnectionProvider, TlsConfig};
186mod hosts;
187pub use hosts::Hosts;
188pub mod lookup;
189pub mod lookup_ip;
190mod name_server;
191pub use name_server::NameServer;
192mod name_server_pool;
193#[cfg(all(feature = "toml", any(feature = "__tls", feature = "__quic")))]
194pub use name_server_pool::OpportunisticEncryptionStatePersistTask;
195pub use name_server_pool::{NameServerPool, NameServerTransportState, PoolContext};
196
197#[cfg(feature = "recursor")]
198pub mod recursor;
199
200mod resolver;
201pub use resolver::LookupFuture;
202#[cfg(feature = "tokio")]
203pub use resolver::TokioResolver;
204pub use resolver::{Resolver, ResolverBuilder};
205mod cache;
206pub use cache::{MAX_TTL, ResponseCache, TtlBounds, TtlConfig};
207#[cfg(feature = "metrics")]
208pub mod metrics;
209pub mod system_conf;
210#[cfg(test)]
211mod tests;
212
213/// returns a version as specified in Cargo.toml
214pub fn version() -> &'static str {
215    env!("CARGO_PKG_VERSION")
216}