netcore/dns.rs
1//! DNS resolution results.
2//!
3//! The stub-vs-upstream distinction matters. `/etc/resolv.conf` on this
4//! machine says `127.0.0.53` but the real server answering queries is
5//! `fe80::dead:beef:feed:cafe%eth0`. Users debugging DNS failures want to
6//! see which server actually answered, not just "the stub."
7
8use std::net::IpAddr;
9use std::time::Duration;
10
11use serde::{Deserialize, Serialize};
12
13use crate::connection::Family;
14
15/// Result of a single DNS resolution attempt.
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub struct DnsResolution {
18 /// The name that was queried.
19 pub queried: String,
20 /// Which resolver path was used.
21 pub via: DnsSource,
22 /// Upstream the stub forwarded to, if known (parsed from `resolvectl`).
23 pub upstream_used: Option<IpAddr>,
24 /// Answers returned for the query.
25 pub answers: Vec<DnsAnswer>,
26 /// How long the resolution took.
27 pub took: Duration,
28 /// True when the answer was served from the resolver's cache.
29 pub cached: bool,
30 /// True when the answer was DNSSEC-validated.
31 pub authenticated: bool,
32 /// Set when the resolver returned an error instead of answers.
33 pub error: Option<DnsError>,
34}
35
36/// Which DNS resolver path was used to answer the query.
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(tag = "kind", content = "addr", rename_all = "snake_case")]
39pub enum DnsSource {
40 /// systemd-resolved or dnsmasq listening on loopback.
41 Stub(IpAddr),
42 /// A non-loopback resolver was queried directly.
43 Direct(IpAddr),
44 /// Multicast DNS / .local.
45 Mdns,
46 /// Libc `getaddrinfo`; the answering server is not known.
47 Libc,
48}
49
50/// A single DNS A or AAAA record returned by a resolver.
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct DnsAnswer {
53 /// The resolved IP address.
54 pub ip: IpAddr,
55 /// Address family of `ip`.
56 pub family: Family,
57 /// Time-to-live in seconds, when reported by the resolver.
58 pub ttl: Option<u32>,
59}
60
61/// A DNS resolution error.
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63#[serde(tag = "kind", rename_all = "snake_case")]
64pub enum DnsError {
65 /// The name does not exist (`NXDOMAIN`).
66 NxDomain,
67 /// The server encountered an internal error (`SERVFAIL`).
68 ServFail,
69 /// The resolver did not respond within the deadline.
70 Timeout,
71 /// Name syntactically invalid or resolver refused.
72 Other(String),
73}