domain/net/client/
mod.rs

1#![cfg_attr(
2    not(feature = "unstable-client-transport"),
3    doc = " The `unstable-client-transport` feature is necessary to enable this module."
4)]
5//! Sending requests and receiving responses.
6//!
7//! This module provides DNS transport protocols that allow sending a DNS
8//! request and receiving the corresponding reply.
9//!
10//! Currently the following transport protocols are supported:
11//! * [dgram] DNS over a datagram protocol, typically UDP.
12//! * [stream] DNS over an octet stream protocol, typically TCP or TLS.
13//!   Only a single connection is supported.
14//!   The transport works as long as the connection continues to exist.
15//! * [multi_stream] This is a layer on top of [stream] where new connections
16//!   are established as old connections are closed (or fail).
17//! * [dgram_stream] This is a combination of [dgram] and [multi_stream].
18//!   This is typically needed because a request over UDP can receive
19//!   a truncated response, which should be retried over TCP.
20//! * [redundant] This transport multiplexes requests over a collection of
21//!   transport connections. The [redundant] transport favors the connection
22//!   with the lowest response time. Any of the other transports can be added
23//!   as upstream transports.
24//! * [load_balancer] This transport distributes requests over a collecton of
25//!   transport connections. The [load_balancer] transport favors connections
26//!   with the shortest outstanding request queue. Any of the other transports
27//!   can be added as upstream transports.
28#![cfg_attr(feature = "unstable-client-cache", doc = "* [cache]:")]
29#![cfg_attr(not(feature = "unstable-client-cache",), doc = "* cache:")]
30//!   This is a simple message cache provided as a pass through
31//!   transport. The cache works with any of the other transports.
32#![cfg_attr(feature = "tsig", doc = "* [tsig]:")]
33#![cfg_attr(not(feature = "tsig",), doc = "* tsig:")]
34//!   This is a TSIG request signer and response verifier provided as a
35//!   pass through transport. The tsig transport works with any upstream
36//!   transports so long as they don't modify the message once signed nor
37//!   modify the response before it can be verified.
38#![cfg_attr(
39    all(
40        feature = "unstable-validator",
41        any(feature = "ring", feature = "openssl")
42    ),
43    doc = "* [validator]:"
44)]
45#![cfg_attr(
46    not(all(
47        feature = "unstable-validator",
48        any(feature = "ring", feature = "openssl")
49    )),
50    doc = "* validator:"
51)]
52//!   This is a DNSSEC validator provided as a pass through transport.
53//!   The validator works with any of the other transports.
54//!
55//! Sending a request and receiving the reply consists of four steps:
56//! 1) Creating a request message,
57//! 2) Creating a DNS transport,
58//! 3) Sending the request, and
59//! 4) Receiving the reply or replies.
60//!
61//! The first and second step are independent and can happen in any order.
62//! The third step uses the resuts of the first and second step.
63//! Finally, the fourth step uses the result of the third step.
64
65//! # Creating a request message
66//!
67//! The DNS transport protocols expect a request message that implements the
68//! [ComposeRequest][request::ComposeRequest] trait.
69//! This trait allows transports to add ENDS(0) options, set flags, etc.
70//! The [RequestMessage][request::RequestMessage] type implements this trait.
71//! The [new][request::RequestMessage::new] method of RequestMessage creates
72//! a new RequestMessage object based an existing messsage (that implements
73//! ```Into<Message<Octs>>```).
74//!
75//! For example:
76//! ```rust
77//! # use domain::base::{Name, MessageBuilder, Rtype};
78//! # use domain::net::client::request::RequestMessage;
79//! let mut msg = MessageBuilder::new_vec();
80//! msg.header_mut().set_rd(true);
81//! let mut msg = msg.question();
82//! msg.push(
83//!     (Name::vec_from_str("example.com").unwrap(), Rtype::AAAA)
84//! ).unwrap();
85//! let req = RequestMessage::new(msg);
86//! ```
87
88//! # Creating a DNS transport
89//!
90//! Creating a DNS transport typically involves creating a configuration
91//! object, creating the underlying network connection, creating the
92//! DNS transport and running a ```run``` method as a separate task. This
93//! is illustrated in the following example:
94//! ```rust
95//! # use domain::net::client::multi_stream;
96//! # use domain::net::client::protocol::TcpConnect;
97//! # use domain::net::client::request::SendRequest;
98//! # use std::net::{IpAddr, SocketAddr};
99//! # use std::str::FromStr;
100//! # use std::time::Duration;
101//! # async fn _test() {
102//! # let server_addr = SocketAddr::new(IpAddr::from_str("::1").unwrap(), 53);
103//! let mut multi_stream_config = multi_stream::Config::default();
104//! multi_stream_config.stream_mut().set_response_timeout(
105//!     Duration::from_millis(100),
106//! );
107//! let tcp_connect = TcpConnect::new(server_addr);
108//! let (tcp_conn, transport) = multi_stream::Connection::with_config(
109//!     tcp_connect, multi_stream_config
110//! );
111//! tokio::spawn(transport.run());
112//! # let req = domain::net::client::request::RequestMessage::new(
113//! #     domain::base::MessageBuilder::new_vec()
114//! # ).unwrap();
115//! # let mut request = tcp_conn.send_request(req);
116//! # }
117//! ```
118//! # Sending the request
119//!
120//! A connection implements the [SendRequest][request::SendRequest] trait.
121//! This trait provides a single method,
122//! [send_request][request::SendRequest::send_request] and returns an object
123//! that provides the response.
124//!
125//! For example:
126//! ```no_run
127//! # use domain::net::client::request::{RequestMessageMulti, SendRequest};
128//! # use std::net::{IpAddr, SocketAddr};
129//! # use std::str::FromStr;
130//! # async fn _test() {
131//! # let (tls_conn, _) = domain::net::client::stream::Connection::<_, RequestMessageMulti<Vec<u8>>>::new(
132//! #     domain::net::client::protocol::TcpConnect::new(
133//! #         SocketAddr::new(IpAddr::from_str("::1").unwrap(), 53)
134//! #     )
135//! # );
136//! # let req = domain::net::client::request::RequestMessage::new(
137//! #     domain::base::MessageBuilder::new_vec()
138//! # ).unwrap();
139//! let mut request = tls_conn.send_request(req);
140//! # }
141//! ```
142//! where ```tls_conn``` is a transport connection for DNS over TLS.
143
144//! # Receiving the response
145//!
146//! The [send_request][request::SendRequest::send_request] method returns an
147//! object that implements the [GetResponse][request::GetResponse] trait.
148//! This trait provides a single method,
149//! [get_response][request::GetResponse::get_response], which returns the
150//! DNS response message or an error. This method is intended to be
151//! cancelation safe.
152//!
153//! For example:
154//! ```no_run
155//! # use crate::domain::net::client::request::{RequestMessageMulti, SendRequest};
156//! # use std::net::{IpAddr, SocketAddr};
157//! # use std::str::FromStr;
158//! # async fn _test() {
159//! # let (tls_conn, _) = domain::net::client::stream::Connection::<_, RequestMessageMulti<Vec<u8>>>::new(
160//! #     domain::net::client::protocol::TcpConnect::new(
161//! #         SocketAddr::new(IpAddr::from_str("::1").unwrap(), 53)
162//! #     )
163//! # );
164//! # let req = domain::net::client::request::RequestMessage::new(
165//! #     domain::base::MessageBuilder::new_vec()
166//! # ).unwrap();
167//! # let mut request = tls_conn.send_request(req);
168//! let reply = request.get_response().await;
169//! # }
170//! ```
171//!
172//! <div class="warning">
173//!
174//! **Support for multiple responses:**
175//!
176//! [RequestMessage][request::RequestMessage] is designed for the most common
177//! use case: single request, single response.
178//!
179//! However, zone transfers (e.g. using the `AXFR` or `IXFR` query types) can
180//! result in multiple responses. Attempting to create a
181//! [RequestMessage][request::RequestMessage] for such a query will result in
182//! [Error::FormError][request::Error::FormError].
183//!
184//! For zone transfers you should use
185//! [RequestMessageMulti][request::RequestMessageMulti] instead which can be
186//! used like so:
187//!
188//! ```no_run
189//! # use crate::domain::net::client::request::{RequestMessage, SendRequestMulti};
190//! # use std::net::{IpAddr, SocketAddr};
191//! # use std::str::FromStr;
192//! # async fn _test() {
193//! # let (conn, _) = domain::net::client::stream::Connection::<RequestMessage<Vec<u8>>, _>::new(
194//! #     domain::net::client::protocol::TcpConnect::new(
195//! #         SocketAddr::new(IpAddr::from_str("::1").unwrap(), 53)
196//! #     )
197//! # );
198//! # let req = domain::net::client::request::RequestMessageMulti::new(
199//! #     domain::base::MessageBuilder::new_vec()
200//! # ).unwrap();
201//! # let mut request = conn.send_request(req);
202//! while let Ok(reply) = request.get_response().await {
203//!     // ...
204//! }
205//! # }
206//! ```
207//!
208//! </div>
209//!
210
211//! # Limitations
212//!
213//! The current implementation has the following limitations:
214//! * The [dgram] transport does not support DNS Cookies
215//!   ([`RFC 7873`](https://tools.ietf.org/html/rfc7873)
216//!   Domain Name System (DNS) Cookies).
217//! * The [multi_stream] transport does not support timeouts or other limits on
218//!   the number of attempts to open a connection. The caller has to
219//!   implement a timeout mechanism.
220#![cfg_attr(
221    feature = "unstable-client-cache",
222    doc = "* The [cache] transport does not support:"
223)]
224#![cfg_attr(
225    not(feature = "unstable-client-cache"),
226    doc = "* The cache transport does not support:"
227)]
228//!   * Prefetching. In this context, prefetching means updating a cache entry
229//!     before it expires.
230//!   * [RFC 8767](https://tools.ietf.org/html/rfc8767)
231//!     (Serving Stale Data to Improve DNS Resiliency)
232//!   * [RFC 7871](https://tools.ietf.org/html/rfc7871)
233//!     (Client Subnet in DNS Queries)
234//!   * [RFC 8198](https://tools.ietf.org/html/rfc8198)
235//!     (Aggressive Use of DNSSEC-Validated Cache)
236
237//! # Example with various transport connections
238//! ```no_run
239#![doc = include_str!("../../../examples/client-transports.rs")]
240//! ```
241
242#![cfg(feature = "unstable-client-transport")]
243#![cfg_attr(docsrs, doc(cfg(feature = "unstable-client-transport")))]
244#![warn(missing_docs)]
245#![warn(clippy::missing_docs_in_private_items)]
246
247#[cfg(feature = "unstable-client-cache")]
248pub mod cache;
249pub mod dgram;
250pub mod dgram_stream;
251pub mod load_balancer;
252pub mod multi_stream;
253pub mod protocol;
254pub mod redundant;
255pub mod request;
256pub mod stream;
257pub mod tsig;
258pub mod validator;
259pub mod validator_test;