use crate::vortix_core::ports::dns::DnsResolver;
use crate::vortix_process::CommandSpec;
const RESOLV_CONF_PATH: &str = "/etc/resolv.conf";
pub struct LinuxDns;
impl DnsResolver for LinuxDns {
fn get_dns_server() -> Option<String> {
try_get_dns_resolvectl()
.or_else(try_get_dns_nmcli)
.or_else(try_get_dns_resolv_conf)
}
}
fn try_get_dns_resolvectl() -> Option<String> {
let output = crate::vortix_process::run_to_output(CommandSpec::oneshot(
"resolvectl",
vec!["status".into()],
))
.ok()?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
let trimmed = line.trim();
if trimmed.starts_with("DNS Servers:") || trimmed.starts_with("Current DNS Server:") {
if let Some(dns) = trimmed.split(':').nth(1) {
let dns = dns.trim().to_string();
let first = dns.split_whitespace().next().unwrap_or("").to_string();
if !first.is_empty() {
return Some(first);
}
}
}
}
None
}
fn try_get_dns_nmcli() -> Option<String> {
let output = crate::vortix_process::run_to_output(CommandSpec::oneshot(
"nmcli",
vec!["dev".into(), "show".into()],
))
.ok()?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8_lossy(&output.stdout);
for line in stdout.lines() {
let trimmed = line.trim();
if trimmed.starts_with("IP4.DNS") {
if let Some(dns) = trimmed.split(':').nth(1) {
let dns = dns.trim().to_string();
if !dns.is_empty() {
return Some(dns);
}
}
}
}
None
}
fn try_get_dns_resolv_conf() -> Option<String> {
let content = std::fs::read_to_string(RESOLV_CONF_PATH).ok()?;
for line in content.lines() {
let trimmed = line.trim();
if trimmed.starts_with("nameserver") {
let dns = trimmed.trim_start_matches("nameserver").trim().to_string();
if !dns.is_empty() {
return Some(dns);
}
}
}
None
}
#[cfg(test)]
mod tests {
#[test]
fn test_parse_resolv_conf() {
let content = "# Generated by NetworkManager\nnameserver 1.1.1.1\nnameserver 8.8.8.8\n";
let mut result = None;
for line in content.lines() {
let trimmed = line.trim();
if trimmed.starts_with("nameserver") {
let dns = trimmed.trim_start_matches("nameserver").trim().to_string();
if !dns.is_empty() {
result = Some(dns);
break;
}
}
}
assert_eq!(result, Some("1.1.1.1".to_string()));
}
}