From 78bd8eea248995a542825a1ace99a963da6df932 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Mon, 6 May 2024 13:41:42 +0200 Subject: [PATCH] dns-api: add feature "impl" So the we can use the api types with our UI crates. Signed-off-by: Dietmar Maurer --- proxmox-dns-api/Cargo.toml | 9 +- proxmox-dns-api/src/lib.rs | 144 +---------------------------- proxmox-dns-api/src/resolv_conf.rs | 144 +++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 142 deletions(-) create mode 100644 proxmox-dns-api/src/resolv_conf.rs diff --git a/proxmox-dns-api/Cargo.toml b/proxmox-dns-api/Cargo.toml index 80212192..a3410621 100644 --- a/proxmox-dns-api/Cargo.toml +++ b/proxmox-dns-api/Cargo.toml @@ -17,6 +17,11 @@ regex.workspace = true serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } -proxmox-sys.workspace = true +proxmox-sys = { workspace = true, optional = true } proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] } -proxmox-product-config.workspace = true \ No newline at end of file +proxmox-product-config = { workspace = true, optional = true } + + +[features] +default = [ "proxmox-product-config/default" ] +impl = [ "dep:proxmox-sys", "proxmox-product-config/impl"] \ No newline at end of file diff --git a/proxmox-dns-api/src/lib.rs b/proxmox-dns-api/src/lib.rs index b997a2f0..649a54d4 100644 --- a/proxmox-dns-api/src/lib.rs +++ b/proxmox-dns-api/src/lib.rs @@ -1,18 +1,3 @@ -use std::sync::Arc; -use std::sync::Mutex; - -use anyhow::Error; -use const_format::concatcp; -use lazy_static::lazy_static; -use proxmox_product_config::ConfigDigest; -use regex::Regex; - -use proxmox_sys::fs::file_get_contents; -use proxmox_sys::fs::replace_file; -use proxmox_sys::fs::CreateOptions; - -use proxmox_schema::api_types::IPRE_STR; - mod api_types; pub use api_types::{DeletableResolvConfProperty, ResolvConf, ResolvConfWithDigest}; pub use api_types::{ @@ -20,128 +5,7 @@ pub use api_types::{ THIRD_DNS_SERVER_SCHEMA, }; -static RESOLV_CONF_FN: &str = "/etc/resolv.conf"; - -/// Read DNS configuration from '/etc/resolv.conf'. -pub fn read_etc_resolv_conf( - expected_digest: Option<&[u8; 32]>, -) -> Result { - let mut config = ResolvConf::default(); - - let mut nscount = 0; - - let raw = file_get_contents(RESOLV_CONF_FN)?; - let digest = ConfigDigest::from_slice(&raw); - - proxmox_product_config::detect_modified_configuration_file(expected_digest, &digest)?; - - let data = String::from_utf8(raw)?; - - lazy_static! { - static ref DOMAIN_REGEX: Regex = Regex::new(r"^\s*(?:search|domain)\s+(\S+)\s*").unwrap(); - static ref SERVER_REGEX: Regex = - Regex::new(concatcp!(r"^\s*nameserver\s+(", IPRE_STR, r")\s*")).unwrap(); - } - - let mut options = String::new(); - - for line in data.lines() { - if let Some(caps) = DOMAIN_REGEX.captures(line) { - config.search = Some(caps[1].to_owned()); - } else if let Some(caps) = SERVER_REGEX.captures(line) { - nscount += 1; - if nscount > 3 { - continue; - }; - let nameserver = Some(caps[1].to_owned()); - match nscount { - 1 => config.dns1 = nameserver, - 2 => config.dns2 = nameserver, - 3 => config.dns3 = nameserver, - _ => continue, - } - } else { - if !options.is_empty() { - options.push('\n'); - } - options.push_str(line); - } - } - - if !options.is_empty() { - config.options = Some(options); - } - - Ok(ResolvConfWithDigest { config, digest }) -} - -/// Update DNS configuration, write result back to '/etc/resolv.conf'. -pub fn update_dns( - update: ResolvConf, - delete: Option>, - digest: Option, -) -> Result<(), Error> { - lazy_static! { - static ref MUTEX: Arc> = Arc::new(Mutex::new(())); - } - - let _guard = MUTEX.lock(); - - let ResolvConfWithDigest { mut config, .. } = read_etc_resolv_conf(digest.as_deref())?; - - if let Some(delete) = delete { - for delete_prop in delete { - match delete_prop { - DeletableResolvConfProperty::Dns1 => { - config.dns1 = None; - } - DeletableResolvConfProperty::Dns2 => { - config.dns2 = None; - } - DeletableResolvConfProperty::Dns3 => { - config.dns3 = None; - } - } - } - } - - if update.search.is_some() { - config.search = update.search; - } - if update.dns1.is_some() { - config.dns1 = update.dns1; - } - if update.dns2.is_some() { - config.dns2 = update.dns2; - } - if update.dns3.is_some() { - config.dns3 = update.dns3; - } - - let mut data = String::new(); - - use std::fmt::Write as _; - if let Some(search) = config.search { - let _ = writeln!(data, "search {}", search); - } - - if let Some(dns1) = config.dns1 { - let _ = writeln!(data, "nameserver {}", dns1); - } - - if let Some(dns2) = config.dns2 { - let _ = writeln!(data, "nameserver {}", dns2); - } - - if let Some(dns3) = config.dns3 { - let _ = writeln!(data, "nameserver {}", dns3); - } - - if let Some(options) = config.options { - data.push_str(&options); - } - - replace_file(RESOLV_CONF_FN, data.as_bytes(), CreateOptions::new(), true)?; - - Ok(()) -} +#[cfg(feature = "impl")] +mod resolv_conf; +#[cfg(feature = "impl")] +pub use resolv_conf::*; diff --git a/proxmox-dns-api/src/resolv_conf.rs b/proxmox-dns-api/src/resolv_conf.rs new file mode 100644 index 00000000..ddcab6ad --- /dev/null +++ b/proxmox-dns-api/src/resolv_conf.rs @@ -0,0 +1,144 @@ +use std::sync::Arc; +use std::sync::Mutex; + +use anyhow::Error; +use const_format::concatcp; +use lazy_static::lazy_static; +use proxmox_product_config::ConfigDigest; +use regex::Regex; + +use proxmox_sys::fs::file_get_contents; +use proxmox_sys::fs::replace_file; +use proxmox_sys::fs::CreateOptions; + +use proxmox_schema::api_types::IPRE_STR; + +use crate::DeletableResolvConfProperty; +use crate::ResolvConf; +use crate::ResolvConfWithDigest; + +static RESOLV_CONF_FN: &str = "/etc/resolv.conf"; + +/// Read DNS configuration from '/etc/resolv.conf'. +pub fn read_etc_resolv_conf( + expected_digest: Option<&ConfigDigest>, +) -> Result { + let mut config = ResolvConf::default(); + + let mut nscount = 0; + + let raw = file_get_contents(RESOLV_CONF_FN)?; + let digest = ConfigDigest::from_slice(&raw); + + digest.detect_modification(expected_digest)?; + + let data = String::from_utf8(raw)?; + + lazy_static! { + static ref DOMAIN_REGEX: Regex = Regex::new(r"^\s*(?:search|domain)\s+(\S+)\s*").unwrap(); + static ref SERVER_REGEX: Regex = + Regex::new(concatcp!(r"^\s*nameserver\s+(", IPRE_STR, r")\s*")).unwrap(); + } + + let mut options = String::new(); + + for line in data.lines() { + if let Some(caps) = DOMAIN_REGEX.captures(line) { + config.search = Some(caps[1].to_owned()); + } else if let Some(caps) = SERVER_REGEX.captures(line) { + nscount += 1; + if nscount > 3 { + continue; + }; + let nameserver = Some(caps[1].to_owned()); + match nscount { + 1 => config.dns1 = nameserver, + 2 => config.dns2 = nameserver, + 3 => config.dns3 = nameserver, + _ => continue, + } + } else { + if !options.is_empty() { + options.push('\n'); + } + options.push_str(line); + } + } + + if !options.is_empty() { + config.options = Some(options); + } + + Ok(ResolvConfWithDigest { config, digest }) +} + +/// Update DNS configuration, write result back to '/etc/resolv.conf'. +pub fn update_dns( + update: ResolvConf, + delete: Option>, + digest: Option, +) -> Result<(), Error> { + lazy_static! { + static ref MUTEX: Arc> = Arc::new(Mutex::new(())); + } + + let _guard = MUTEX.lock(); + + let ResolvConfWithDigest { mut config, .. } = read_etc_resolv_conf(digest.as_ref())?; + + if let Some(delete) = delete { + for delete_prop in delete { + match delete_prop { + DeletableResolvConfProperty::Dns1 => { + config.dns1 = None; + } + DeletableResolvConfProperty::Dns2 => { + config.dns2 = None; + } + DeletableResolvConfProperty::Dns3 => { + config.dns3 = None; + } + } + } + } + + if update.search.is_some() { + config.search = update.search; + } + if update.dns1.is_some() { + config.dns1 = update.dns1; + } + if update.dns2.is_some() { + config.dns2 = update.dns2; + } + if update.dns3.is_some() { + config.dns3 = update.dns3; + } + + let mut data = String::new(); + + use std::fmt::Write as _; + if let Some(search) = config.search { + let _ = writeln!(data, "search {}", search); + } + + if let Some(dns1) = config.dns1 { + let _ = writeln!(data, "nameserver {}", dns1); + } + + if let Some(dns2) = config.dns2 { + let _ = writeln!(data, "nameserver {}", dns2); + } + + if let Some(dns3) = config.dns3 { + let _ = writeln!(data, "nameserver {}", dns3); + } + + if let Some(options) = config.options { + data.push_str(&options); + } + + replace_file(RESOLV_CONF_FN, data.as_bytes(), CreateOptions::new(), true)?; + + Ok(()) +}