Skip to main content

setdns/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod config;
4mod error;
5mod platform;
6
7pub use config::Config;
8pub use error::{Error, Result};
9
10/// Applied DNS configuration handle.
11///
12/// The DNS configuration stays active while this value is alive. Call
13/// [`SetDns::close`] to restore the previous state and receive any restore
14/// error. Dropping the handle also attempts restoration, but drop-time errors
15/// can only be logged.
16#[must_use = "the DNS configuration is restored when the handle is dropped"]
17pub struct SetDns(Option<platform::SetDns>);
18
19impl SetDns {
20    /// Validate and apply a DNS configuration.
21    ///
22    /// Returns [`Error::InvalidConfig`] before touching the platform backend if
23    /// the configuration is malformed. Platform, permission, D-Bus,
24    /// SystemConfiguration, Windows API, registry, and I/O failures are
25    /// returned as [`Error::Backend`].
26    pub fn apply(config: Config) -> Result<Self> {
27        let config = config.normalize()?;
28        log::debug!(
29            "applying DNS configuration: mode={}, servers={}, domains={}, device={}",
30            if config.domains.is_empty() {
31                "global"
32            } else {
33                "split"
34            },
35            config.servers.len(),
36            config.domains.len(),
37            config.device.as_deref().unwrap_or("default")
38        );
39        let inner = platform::SetDns::apply(config)?;
40        log::info!("applied DNS configuration");
41        Ok(Self(Some(inner)))
42    }
43
44    /// Restore the previous DNS configuration and consume this handle.
45    ///
46    /// Calling `close` is preferred over relying on `Drop` because this method
47    /// reports restore failures to the caller.
48    pub fn close(mut self) -> Result<()> {
49        if let Some(inner) = self.0.take() {
50            inner.close()?;
51            log::info!("restored DNS configuration");
52        }
53        Ok(())
54    }
55}
56
57impl Drop for SetDns {
58    fn drop(&mut self) {
59        if let Some(inner) = self.0.take()
60            && let Err(err) = inner.close()
61        {
62            log::warn!("failed to restore DNS configuration for setdns: {err}");
63        }
64    }
65}