Skip to main content

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}