#![allow(missing_debug_implementations)]
use std::fs;
use std::io::Write;
use std::path::PathBuf;
#[derive(Clone, Copy, Debug)]
pub enum ResolvConfMode {
Stub,
Uplink,
Foreign,
}
pub struct ResolvConfPublisher {
pub run_dir: PathBuf, pub mode: ResolvConfMode,
}
impl ResolvConfPublisher {
pub fn ensure_dirs(&self) -> std::io::Result<()> {
fs::create_dir_all(&self.run_dir)?;
fs::create_dir_all(self.run_dir.join("netif"))?;
Ok(())
}
pub fn write_stub(&self, search: &[String], options: &str) -> std::io::Result<()> {
let p = self.run_dir.join("stub-resolv.conf");
let mut tmp = p.clone();
tmp.set_extension("tmp");
let mut f = fs::File::create(&tmp)?;
writeln!(f, "# Written by systemd-resolved-rs")?;
writeln!(f, "nameserver 127.0.0.53")?;
writeln!(f, "nameserver 127.0.0.54")?; if !search.is_empty() {
writeln!(f, "search {}", search.join(" "))?;
}
if !options.is_empty() {
writeln!(f, "options {options}")?;
}
f.sync_all()?;
fs::rename(tmp, p)?;
Ok(())
}
pub fn write_uplink(
&self,
servers: &[std::net::IpAddr],
search: &[String],
) -> std::io::Result<()> {
let p = self.run_dir.join("resolv.conf");
let mut tmp = p.clone();
tmp.set_extension("tmp");
let mut f = fs::File::create(&tmp)?;
writeln!(f, "# Uplink resolv.conf from systemd-resolved-rs")?;
for s in servers {
writeln!(f, "nameserver {s}")?;
}
if !search.is_empty() {
writeln!(f, "search {}", search.join(" "))?;
}
f.sync_all()?;
fs::rename(tmp, p)?;
Ok(())
}
pub fn write_netif(
&self,
ifindex: i32,
servers: &[std::net::IpAddr],
search: &[String],
) -> std::io::Result<()> {
let p = self.run_dir.join("netif").join(ifindex.to_string());
let mut tmp = p.clone();
tmp.set_extension("tmp");
let mut f = fs::File::create(&tmp)?;
writeln!(f, "# Link {ifindex} state")?;
for s in servers {
writeln!(f, "nameserver {s}")?;
}
if !search.is_empty() {
writeln!(f, "search {}", search.join(" "))?;
}
f.sync_all()?;
fs::rename(tmp, p)?;
Ok(())
}
pub fn republish(&self, state: &GlobalDnsState) -> std::io::Result<()> {
self.ensure_dirs()?;
self.write_stub(&state.search, "edns0 trust-ad")?;
self.write_uplink(&state.uplink_servers, &state.search)?;
Ok(())
}
}
pub struct GlobalDnsState {
pub search: Vec<String>,
pub uplink_servers: Vec<std::net::IpAddr>,
}