tailscale_rest/models/dns.rs
1//! The tailnet's DNS: nameservers, search paths, split DNS and MagicDNS.
2//!
3//! The description carries two generations of this. The older endpoints take
4//! and return the pieces separately — [`DnsPreferences`], [`DnsSearchPaths`]
5//! and a `SplitDns` map of domain to plain address strings — while
6//! [`DnsConfiguration`] is the whole thing at once, and spells its split DNS
7//! as a map of domain to [`DnsConfigurationResolver`]. Both are modelled,
8//! unrenamed, because both are still served.
9//!
10//! `SplitDns` itself has no struct here: it is a bare map with no properties,
11//! so there is nothing for a drift test to check and nothing for a model to
12//! hold that [`std::collections::BTreeMap`] does not.
13
14use std::collections::BTreeMap;
15
16use crate::model;
17use crate::models::KnownValues;
18
19pub const KNOWN_VALUES: &[KnownValues] = &[];
20
21/// The older split-DNS shape: a domain suffix to the nameservers that answer
22/// for it, or to `null` to remove the suffix.
23pub type SplitDns = BTreeMap<String, Option<Vec<String>>>;
24
25model! {
26 /// The tailnet's global nameservers.
27 ///
28 /// Sent to set them and returned when reading them; the same shape both
29 /// ways, which is why one struct serves three of the description's places.
30 DnsNameservers as "GET /tailnet/{tailnet}/dns/nameservers 200" {
31 /// Addresses, not URLs. Replacing this with an empty list removes
32 /// every global nameserver, which also turns MagicDNS off.
33 dns: "dns" => Vec<String>,
34 }
35
36 /// The same list, as the request that replaces it.
37 DnsNameserversRequest as "POST /tailnet/{tailnet}/dns/nameservers body" is DnsNameservers;
38
39 /// What replacing the nameservers answers with: the new list, and the
40 /// state MagicDNS was left in.
41 DnsNameserversSet as "POST /tailnet/{tailnet}/dns/nameservers 200" {
42 dns: "dns" => Vec<String>,
43 /// Turns itself off when the last nameserver goes, which is why the
44 /// answer says so rather than leaving a caller to read it back.
45 magic_dns: "magicDNS" => bool,
46 }
47
48 /// Whether MagicDNS is on.
49 DnsPreferences {
50 /// Turning this on requires at least one global nameserver.
51 magic_dns: "magicDNS" => bool,
52 }
53
54 /// The search domains appended to a bare name.
55 DnsSearchPaths {
56 search_paths: "searchPaths" => Vec<String>,
57 }
58
59 /// One nameserver, and whether it survives an exit node.
60 DnsConfigurationResolver {
61 /// An address of either family, not a URL.
62 address: "address" => String,
63 /// Keep using this resolver while the device is on an exit node.
64 /// Needs Tailscale 1.88.1 or later on the device.
65 use_with_exit_node: "useWithExitNode" => bool,
66 }
67
68 /// MagicDNS, and whether the tailnet's nameservers replace the machine's.
69 DnsConfigurationPreferences {
70 /// `true` makes `nameservers` the resolvers; `false` leaves them as a
71 /// fallback behind whatever the OS is configured with.
72 override_local_dns: "overrideLocalDNS" => bool,
73 /// MagicDNS, which needs a global nameserver to be on.
74 magic_dns: "magicDNS" => bool,
75 }
76
77 /// The whole DNS configuration in one document.
78 DnsConfiguration {
79 nameservers: "nameservers" => Vec<DnsConfigurationResolver>,
80 /// Domain suffix to the resolvers that answer for it, or to `null` to
81 /// remove the suffix. Note the resolvers here are objects, where the
82 /// older `SplitDns` shape spells them as addresses.
83 split_dns: "splitDNS" => BTreeMap<String, Option<Vec<DnsConfigurationResolver>>>,
84 search_paths: "searchPaths" => Vec<String>,
85 preferences: "preferences" => DnsConfigurationPreferences,
86 }
87}