doh_dns/lib.rs
1//! Library to make DNS over HTTPS requests.
2//!
3//! This DNS over HTTPS (DoH) library queries public DoH servers provided by Google and
4//! Clouflare. It is based on `async/await` with the help of `hyper` and `tokio`.
5//!
6//! The library supports timeouts and retries which can be fully customized. A utility
7//! is provided in this crate to use this library in the command line.
8//!
9//! # Quick Start
10//!
11//! To quickly get started, a default client can be created with `Dns:default` and
12//! `A` records can be queried using [Dns::resolve_a]. The default resolvers use Google
13//! first with a timeout of 3 seconds and Clouflare second with a timeout of 10 seconds.
14//! *Note: Cloudlare does not support queries for `ANY` records. You can use the Google
15//! resolver for that.
16//!
17//! # Example
18//! ```
19//! use doh_dns::{client::HyperDnsClient, Dns, DnsHttpsServer};
20//! use std::time::Duration;
21//! use tokio;
22//!
23//! #[tokio::main]
24//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
25//! // The following sets up the main DoH server to be Google with a default timeout
26//! // of 2 seconds. If a retry is needed, the Cloudflare's 1.1.1.1 server is used.
27//! // Alternatively, the default server setup can be used with:
28//! // let dns = Dns::default();
29//! let dns: Dns<HyperDnsClient> = Dns::with_servers(&[
30//! DnsHttpsServer::Google(Duration::from_secs(2)),
31//! DnsHttpsServer::Cloudflare1_1_1_1(Duration::from_secs(10)),
32//! ])
33//! .unwrap();
34//! match dns.resolve_a("memo.com").await {
35//! Ok(responses) => {
36//! if responses.is_empty() {
37//! println!("No entries found.");
38//! } else {
39//! for res in responses {
40//! println!(
41//! "name: {}, type: {}, TTL: {}, data: {}",
42//! res.name,
43//! dns.rtype_to_name(res.r#type),
44//! res.TTL,
45//! res.data
46//! );
47//! }
48//! }
49//! }
50//! Err(err) => println!("Error: {}", err),
51//! }
52//! Ok(())
53//! }
54//! ```
55//!
56//! # Logging
57//! This library uses the `log` crate to log errors during retries. Please see that create
58//! on methods on display such errors. If no logger is setup, nothing will be logged.
59#![feature(proc_macro_hygiene)]
60#![feature(stmt_expr_attributes)]
61pub mod client;
62mod dns;
63pub mod error;
64pub mod status;
65#[macro_use]
66extern crate serde_derive;
67extern crate num;
68#[macro_use]
69extern crate num_derive;
70use std::time::Duration;
71
72/// The data associated for requests returned by the DNS over HTTPS servers.
73#[allow(non_snake_case)]
74#[derive(Deserialize, Debug, Serialize, Clone)]
75pub struct DnsAnswer {
76 /// The name of the record.
77 pub name: String,
78 /// The type associated with each record. To convert to a string representation use
79 /// [Dns::rtype_to_name].
80 pub r#type: u32,
81 /// The time to live in seconds for this record.
82 pub TTL: u32,
83 /// The data associated with the record.
84 pub data: String,
85}
86
87#[allow(non_snake_case)]
88#[derive(Deserialize, Debug, Serialize)]
89struct DnsResponse {
90 Status: u32,
91 Answer: Option<Vec<DnsAnswer>>,
92 Comment: Option<String>,
93}
94
95/// The list of DNS over HTTPS servers allowed to query with their respective timeouts.
96/// These servers are given to [Dns::with_servers] in order of priority. Only subsequent
97/// servers are used if the request needs to be retried.
98#[derive(Clone)]
99pub enum DnsHttpsServer {
100 /// Googe's DoH server. Unfortunately, Google doesn't allow to query `8.8.8.8` or
101 /// `8.8.4.4` directly. It needs the hostname `dns.google`. If this option is
102 /// given, `8.8.8.8` and `8.8.4.4` will be used in round robin form for each new
103 /// connection.
104 Google(Duration),
105 /// Cloudflare's `1.1.1.1` DOH server. Cloudflare does not respond to `ANY` Dns
106 /// requests so [Dns::resolve_any] will always return an error.
107 Cloudflare1_1_1_1(Duration),
108 /// Cloudflare's `1.0.0.1` DOH server. Cloudflare does not respond to `ANY` Dns
109 /// requests so [Dns::resolve_any] will always return an error.
110 Cloudflare1_0_0_1(Duration),
111}
112
113impl DnsHttpsServer {
114 fn uri(&self) -> &str {
115 match self {
116 Self::Google(_) => "https://dns.google/resolve",
117 Self::Cloudflare1_1_1_1(_) => "https://1.1.1.1/dns-query",
118 Self::Cloudflare1_0_0_1(_) => "https://1.0.0.1/dns-query",
119 }
120 }
121 fn timeout(&self) -> Duration {
122 match self {
123 Self::Google(t) => *t,
124 Self::Cloudflare1_1_1_1(t) => *t,
125 Self::Cloudflare1_0_0_1(t) => *t,
126 }
127 }
128}
129
130/// The main interface to this library. It provides all functions to query records.
131pub struct Dns<C: client::DnsClient> {
132 client: C,
133 servers: Vec<DnsHttpsServer>,
134}