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//! There are two types for performing DNS queries, [`Resolver`] and [`AsyncResolver`]. `Resolver`
21//! is the easiest to work with, it is a wrapper around [`AsyncResolver`]. `AsyncResolver` is a
22//! `Tokio` based async resolver, and can be used inside any `Tokio` based system.
23//!
24//! This as best as possible attempts to abide by the DNS RFCs, please file issues at
25//! <https://github.com/hickory-dns/hickory-dns>.
26//!
27//! # Usage
28//!
29//! ## Declare dependency
30//!
31//! ```toml
32//! [dependency]
33//! hickory-resolver = "*"
34//! ```
35//!
36//! ## Using the Synchronous Resolver
37//!
38//! This uses the default configuration, which sets the [Google Public
39//! DNS](https://developers.google.com/speed/public-dns/) as the upstream resolvers. Please see
40//! their [privacy statement](https://developers.google.com/speed/public-dns/privacy) for important
41//! information about what they track, many ISP's track similar information in DNS.
42//!
43//! ```rust
44//! # fn main() {
45//! # #[cfg(feature = "tokio-runtime")]
46//! # {
47//! use std::net::*;
48//! use hickory_resolver::Resolver;
49//! use hickory_resolver::config::*;
50//!
51//! // Construct a new Resolver with default configuration options
52//! let resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default()).unwrap();
53//!
54//! // Lookup the IP addresses associated with a name.
55//! // The final dot forces this to be an FQDN, otherwise the search rules as specified
56//! //  in `ResolverOpts` will take effect. FQDN's are generally cheaper queries.
57//! let response = resolver.lookup_ip("www.example.com.").unwrap();
58//!
59//! // There can be many addresses associated with the name,
60//! //  this can return IPv4 and/or IPv6 addresses
61//! let address = response.iter().next().expect("no addresses returned!");
62//! if address.is_ipv4() {
63//!     assert_eq!(address, IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)));
64//! } else {
65//!     assert_eq!(address, IpAddr::V6(Ipv6Addr::new(0x2606, 0x2800, 0x220, 0x1, 0x248, 0x1893, 0x25c8, 0x1946)));
66//! }
67//! # }
68//! # }
69//! ```
70//!
71//! ## Using the host system config
72//!
73//! On Unix systems, the `/etc/resolv.conf` can be used for configuration. Not all options
74//! specified in the host systems `resolv.conf` are applicable or compatible with this software. In
75//! addition there may be additional options supported which the host system does not. Example:
76//!
77//! ```rust,no_run
78//! # fn main() {
79//! # #[cfg(feature = "tokio-runtime")]
80//! # {
81//! # use std::net::*;
82//! # use hickory_resolver::Resolver;
83//! // Use the host OS'es `/etc/resolv.conf`
84//! # #[cfg(unix)]
85//! let resolver = Resolver::from_system_conf().unwrap();
86//! # #[cfg(unix)]
87//! let response = resolver.lookup_ip("www.example.com.").unwrap();
88//! # }
89//! # }
90//! ```
91//!
92//! ## Using the Tokio/Async Resolver
93//!
94//! For more advanced asynchronous usage, the `AsyncResolver`] is integrated with Tokio. In fact,
95//! the [`AsyncResolver`] is used by the synchronous Resolver for all lookups.
96//!
97//! ```rust
98//! # fn main() {
99//! # #[cfg(feature = "tokio-runtime")]
100//! # {
101//! use std::net::*;
102//! use tokio::runtime::Runtime;
103//! use hickory_resolver::TokioAsyncResolver;
104//! use hickory_resolver::config::*;
105//!
106//! // We need a Tokio Runtime to run the resolver
107//! //  this is responsible for running all Future tasks and registering interest in IO channels
108//! let mut io_loop = Runtime::new().unwrap();
109//!
110//! // Construct a new Resolver with default configuration options
111//! let resolver = io_loop.block_on(async {
112//!     TokioAsyncResolver::tokio(
113//!         ResolverConfig::default(),
114//!         ResolverOpts::default())
115//! });
116//!
117//! // Lookup the IP addresses associated with a name.
118//! // This returns a future that will lookup the IP addresses, it must be run in the Core to
119//! //  to get the actual result.
120//! let lookup_future = resolver.lookup_ip("www.example.com.");
121//!
122//! // Run the lookup until it resolves or errors
123//! let mut response = io_loop.block_on(lookup_future).unwrap();
124//!
125//! // There can be many addresses associated with the name,
126//! //  this can return IPv4 and/or IPv6 addresses
127//! let address = response.iter().next().expect("no addresses returned!");
128//! if address.is_ipv4() {
129//!     assert_eq!(address, IpAddr::V4(Ipv4Addr::new(93, 184, 216, 34)));
130//! } else {
131//!     assert_eq!(address, IpAddr::V6(Ipv6Addr::new(0x2606, 0x2800, 0x220, 0x1, 0x248, 0x1893, 0x25c8, 0x1946)));
132//! }
133//! # }
134//! # }
135//! ```
136//!
137//! Generally after a lookup in an asynchronous context, there would probably be a connection made
138//! to a server, for example:
139//!
140//! ```rust,no_run
141//! # fn main() {
142//! # #[cfg(feature = "tokio-runtime")]
143//! # {
144//! # use std::net::*;
145//! # use tokio::runtime::Runtime;
146//! # use hickory_resolver::TokioAsyncResolver;
147//! # use hickory_resolver::config::*;
148//! # use futures_util::TryFutureExt;
149//! #
150//! # let mut io_loop = Runtime::new().unwrap();
151//! #
152//! # let resolver = io_loop.block_on(async {
153//! #    TokioAsyncResolver::tokio(
154//! #        ResolverConfig::default(),
155//! #        ResolverOpts::default())
156//! # });
157//! #
158//! let ips = io_loop.block_on(resolver.lookup_ip("www.example.com.")).unwrap();
159//!
160//! let result = io_loop.block_on(async {
161//!     let ip = ips.iter().next().unwrap();
162//!     TcpStream::connect((ip, 443))
163//! })
164//! .and_then(|conn| Ok(conn) /* do something with the connection... */)
165//! .unwrap();
166//! # }
167//! # }
168//! ```
169//!
170//! It's beyond the scope of these examples to show how to deal with connection failures and
171//! looping etc. But if you wanted to say try a different address from the result set after a
172//! connection failure, it will be necessary to create a type that implements the `Future` trait.
173//! Inside the `Future::poll` method would be the place to implement a loop over the different IP
174//! addresses.
175//!
176//! ## DNS-over-TLS and DNS-over-HTTPS
177//!
178//! DNS-over-TLS and DNS-over-HTTPS are supported in the Hickory DNS Resolver library. The underlying
179//! implementations are available as addon libraries. *WARNING* The hickory-dns developers make no
180//! claims on the security and/or privacy guarantees of this implementation.
181//!
182//! To use DNS-over-TLS one of the `dns-over-tls` features must be enabled at compile time. There
183//! are three: `dns-over-openssl`, `dns-over-native-tls`, and `dns-over-rustls`. For DNS-over-HTTPS
184//! only rustls is supported with the `dns-over-https-rustls`, this implicitly enables support for
185//! DNS-over-TLS as well. The reason for each is to make the Hickory DNS libraries flexible for
186//! different deployments, and/or security concerns. The easiest to use will generally be
187//! `dns-over-rustls` which utilizes the `*ring*` Rust cryptography library (a rework of the
188//! `boringssl` project), this should compile and be usable on most ARM and x86 platforms.
189//! `dns-over-native-tls` will utilize the hosts TLS implementation where available or fallback to
190//! `openssl` where not supported. `dns-over-openssl` will specify that `openssl` should be used
191//! (which is a perfectly fine option if required). If more than one is specified, the precedence
192//! will be in this order (i.e. only one can be used at a time) `dns-over-rustls`,
193//! `dns-over-native-tls`, and then `dns-over-openssl`. **NOTICE** the Hickory DNS developers are not
194//! responsible for any choice of library that does not meet required security requirements.
195//!
196//! ### Example
197//!
198//! Enable the TLS library through the dependency on `hickory-resolver`:
199//!
200//! ```toml
201//! hickory-resolver = { version = "*", features = ["dns-over-rustls"] }
202//! ```
203//!
204//! A default TLS configuration is available for Cloudflare's `1.1.1.1` DNS service (Quad9 as
205//! well):
206//!
207//! ```rust,no_run
208//! # fn main() {
209//! # #[cfg(feature = "tokio-runtime")]
210//! # {
211//! use hickory_resolver::Resolver;
212//! use hickory_resolver::config::*;
213//!
214//! // Construct a new Resolver with default configuration options
215//! # #[cfg(feature = "dns-over-tls")]
216//! let mut resolver = Resolver::new(ResolverConfig::cloudflare_tls(), ResolverOpts::default()).unwrap();
217//!
218//! // see example above...
219//! # }
220//! # }
221//! ```
222//!
223//! ## mDNS (multicast DNS)
224//!
225//! Multicast DNS is an experimental feature in Hickory DNS at the moment. Its support on different
226//! platforms is not yet ideal. Initial support is only for IPv4 mDNS, as there are some
227//! complexities to figure out with IPv6. Once enabled, an mDNS `NameServer` will automatically be
228//! added to the `Resolver` and used for any lookups performed in the `.local.` zone.
229
230// LIBRARY WARNINGS
231#![warn(
232    clippy::default_trait_access,
233    clippy::dbg_macro,
234    clippy::print_stdout,
235    clippy::unimplemented,
236    clippy::use_self,
237    missing_copy_implementations,
238    missing_docs,
239    non_snake_case,
240    non_upper_case_globals,
241    rust_2018_idioms,
242    unreachable_pub
243)]
244#![recursion_limit = "128"]
245#![allow(clippy::needless_doctest_main, clippy::single_component_path_imports)]
246#![cfg_attr(docsrs, feature(doc_cfg))]
247
248#[cfg(feature = "dns-over-tls")]
249#[macro_use]
250extern crate cfg_if;
251#[cfg(feature = "serde-config")]
252#[macro_use]
253extern crate serde;
254pub extern crate hickory_proto as proto;
255
256mod async_resolver;
257pub mod caching_client;
258pub mod config;
259pub mod dns_lru;
260pub mod dns_sd;
261pub mod error;
262#[cfg(feature = "dns-over-https")]
263mod h2;
264#[cfg(feature = "dns-over-h3")]
265mod h3;
266mod hosts;
267pub mod lookup;
268pub mod lookup_ip;
269// TODO: consider #[doc(hidden)]
270pub mod name_server;
271#[cfg(feature = "dns-over-quic")]
272mod quic;
273#[cfg(feature = "tokio-runtime")]
274mod resolver;
275pub mod system_conf;
276#[cfg(feature = "dns-over-tls")]
277mod tls;
278
279// reexports from proto
280pub use self::proto::rr::{IntoName, Name, TryParseIp};
281
282#[cfg(feature = "testing")]
283#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
284pub use async_resolver::testing;
285pub use async_resolver::AsyncResolver;
286#[cfg(feature = "tokio-runtime")]
287#[cfg_attr(docsrs, doc(cfg(feature = "tokio-runtime")))]
288pub use async_resolver::TokioAsyncResolver;
289pub use hosts::Hosts;
290#[cfg(feature = "tokio-runtime")]
291#[cfg_attr(docsrs, doc(cfg(feature = "tokio-runtime")))]
292pub use name_server::TokioHandle;
293#[cfg(feature = "tokio-runtime")]
294#[cfg_attr(docsrs, doc(cfg(feature = "tokio-runtime")))]
295pub use resolver::Resolver;
296
297/// This is an alias for [`AsyncResolver`], which replaced the type previously
298/// called `ResolverFuture`.
299///
300/// # Note
301///
302/// For users of `ResolverFuture`, the return type for `ResolverFuture::new`
303/// has changed since version 0.9 of `hickory-resolver`. It now returns
304/// a tuple of an [`AsyncResolver`] _and_ a background future, which must
305/// be spawned on a reactor before any lookup futures will run.
306///
307/// See the [`AsyncResolver`] documentation for more information on how to
308/// use the background future.
309#[deprecated(note = "use [`hickory_resolver::AsyncResolver`] instead")]
310#[cfg(feature = "tokio-runtime")]
311#[cfg_attr(docsrs, doc(cfg(feature = "tokio-runtime")))]
312pub type ResolverFuture = TokioAsyncResolver;
313
314/// returns a version as specified in Cargo.toml
315pub fn version() -> &'static str {
316    env!("CARGO_PKG_VERSION")
317}