From 860d95242e8706cfe5e25b5474b0e9a9276cd6f8 Mon Sep 17 00:00:00 2001 From: Guillermo Roche Date: Fri, 5 Dec 2025 15:12:17 +0000 Subject: [PATCH] enable multiple dns servers --- Cargo.lock | 1 + config_template.toml | 17 +++++++--- dns-comunications/Cargo.toml | 1 + dns-comunications/src/lib.rs | 58 +++++++++++++++++++++------------- dns-comunications/src/utils.rs | 22 +++++++++++++ dns-config/src/lib.rs | 38 ++++++++++++++-------- src/main.rs | 18 +++++------ 7 files changed, 106 insertions(+), 49 deletions(-) create mode 100644 dns-comunications/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 94642be..85dad40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,7 @@ name = "dns-comunications" version = "0.1.0" dependencies = [ "base64 0.22.1", + "dns-config", "dns-update", ] diff --git a/config_template.toml b/config_template.toml index ddc13b2..a99af44 100644 --- a/config_template.toml +++ b/config_template.toml @@ -1,7 +1,16 @@ -[key] +[zone] +root_domain = "root.domain.example" + +[[server]] +conection_str = "tcp://127.0.0.1:53" + +[server.key] name = "key name" value = "key in base64" -[zone] -root_domain = "root.domain.example" -conection_str = "tcp://127.0.0.1:53" +[[server]] +conection_str = "udp://192.168.1.1:53" + +[server.key] +name = "key name" +value = "key in base64" diff --git a/dns-comunications/Cargo.toml b/dns-comunications/Cargo.toml index d704e2b..51240ba 100644 --- a/dns-comunications/Cargo.toml +++ b/dns-comunications/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] dns-update = "0.1" base64 = "*" +dns-config = {path = "../dns-config"} diff --git a/dns-comunications/src/lib.rs b/dns-comunications/src/lib.rs index aba0ef4..99a0107 100644 --- a/dns-comunications/src/lib.rs +++ b/dns-comunications/src/lib.rs @@ -1,39 +1,53 @@ use std::net::Ipv4Addr; -use dns_update::{DnsRecord, DnsRecordType, DnsUpdater, TsigAlgorithm}; -use base64::engine::general_purpose::STANDARD; use base64::Engine; +use base64::engine::general_purpose::STANDARD; +use dns_update::{DnsUpdater, TsigAlgorithm}; + +use dns_config::ServerZonesConnection; + +mod utils; pub struct DnsManager { - pub dns_updater: DnsUpdater, - pub zone: String + pub dns_updaters: Vec, + pub zone: String, } impl DnsManager { - pub fn new(conection_str: String, key_name: String, key: String, zone: String) -> Self { - Self { - dns_updater: DnsUpdater::new_rfc2136_tsig( - conection_str, - key_name, - STANDARD.decode(key).unwrap(), - TsigAlgorithm::HmacSha256.into() - ).unwrap(), - zone + pub fn new(zones_data: ServerZonesConnection) -> Result { + let mut dns_updaters = Vec::new(); + for zone_data in zones_data.servers_data { + dns_updaters.push(DnsUpdater::new_rfc2136_tsig( + zone_data.conection_str, + zone_data.key_name, + #[allow(unreachable_code)] + STANDARD.decode(zone_data.key).unwrap_or(continue), + TsigAlgorithm::HmacSha256.into(), + )?); } + Ok(Self { + dns_updaters, + zone: zones_data.root_domain, + }) } - pub async fn add_domain(&self, domain_name: &String, domain_ip: Ipv4Addr) { + pub async fn add_domain( + &self, + domain_name: &String, + domain_ip: Ipv4Addr, + ) -> Result<(), dns_update::Error> { let domain = format!("{}.{}", domain_name, self.zone); - self.dns_updater.create( - domain, - DnsRecord::A { content: domain_ip }, - 300, - self.zone.clone() - ).await.unwrap(); + for dns_updater in &self.dns_updaters { + utils::add_domain(dns_updater, &domain, &self.zone, domain_ip).await?; + } + Ok(()) } - pub async fn del_domain(&self, domain_name: &String) { + pub async fn del_domain(&self, domain_name: &String) -> Result<(), dns_update::Error> { let domain = format!("{}.{}", domain_name, self.zone); - self.dns_updater.delete(domain, self.zone.clone(), DnsRecordType::A).await.unwrap(); + for dns_updater in &self.dns_updaters { + utils::del_domain(dns_updater, &domain, &self.zone).await?; + } + Ok(()) } } diff --git a/dns-comunications/src/utils.rs b/dns-comunications/src/utils.rs new file mode 100644 index 0000000..93d6c47 --- /dev/null +++ b/dns-comunications/src/utils.rs @@ -0,0 +1,22 @@ +use std::net::Ipv4Addr; + +use dns_update::{DnsRecord, DnsRecordType, DnsUpdater}; + +pub async fn add_domain( + dns_updater: &DnsUpdater, + domain: &str, + zone: &str, + domain_ip: Ipv4Addr, +) -> Result<(), dns_update::Error> { + dns_updater + .create(domain, DnsRecord::A { content: domain_ip }, 300, zone) + .await +} + +pub async fn del_domain( + dns_updater: &DnsUpdater, + domain: &str, + zone: &str, +) -> Result<(), dns_update::Error> { + dns_updater.delete(domain, zone, DnsRecordType::A).await +} diff --git a/dns-config/src/lib.rs b/dns-config/src/lib.rs index 37c43bd..00e6bce 100644 --- a/dns-config/src/lib.rs +++ b/dns-config/src/lib.rs @@ -1,36 +1,46 @@ use std::fs::read_to_string; use toml::Table; -pub struct KeyData { +pub struct ZoneConnectionData { + pub conection_str: String, pub key_name: String, pub key: String, } -pub struct ZoneData { +pub struct ServerZonesConnection { pub root_domain: String, - pub conection_str: String, + pub servers_data: Vec, } -impl KeyData { - pub fn get_config(file_name: &String) -> Self { +impl ZoneConnectionData { + pub fn get_config(file_name: &String) -> Vec { + let mut ret = Vec::new(); let key_toml = read_to_string(file_name).unwrap().parse::().unwrap(); - let name: String = key_toml["key"]["name"].as_str().unwrap().to_string(); - let value: String = key_toml["key"]["value"].as_str().unwrap().to_string(); - Self { - key_name: name, - key: value + for servers in key_toml["server"].as_array().unwrap() { + let conection_str: String = servers["connection_str"].as_str().unwrap().to_string(); + let key_name: String = servers["key"]["name"].as_str().unwrap().to_string(); + let key: String = servers["key"]["value"].as_str().unwrap().to_string(); + ret.push(Self { + conection_str, + key_name, + key, + }); } + ret } } -impl ZoneData { +impl ServerZonesConnection { pub fn get_config(file_name: &String) -> Self { let key_toml = read_to_string(file_name).unwrap().parse::
().unwrap(); - let root_domain: String = key_toml["zone"]["root_domain"].as_str().unwrap().to_string(); - let conection_str: String = key_toml["zone"]["conection_str"].as_str().unwrap().to_string(); + let root_domain: String = key_toml["zone"]["root_domain"] + .as_str() + .unwrap() + .to_string(); + Self { root_domain, - conection_str + servers_data: ZoneConnectionData::get_config(file_name), } } } diff --git a/src/main.rs b/src/main.rs index d090f21..f58adf7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,14 +5,14 @@ use dns_config; #[tokio::main] async fn main() { - let key = dns_config::KeyData::get_config(&"config.toml".to_string()); - let zone = dns_config::ZoneData::get_config(&"config.toml".to_string()); - let dns_manager = dns_comunications::DnsManager::new( - zone.conection_str, - key.key_name, - key.key, - zone.root_domain); + let zone_data = dns_config::ServerZonesConnection::get_config(&"config.toml".to_string()); + let dns_manager = dns_comunications::DnsManager::new(zone_data).unwrap(); - dns_manager.add_domain(&"test001".to_string(), Ipv4Addr::from_str("1.1.1.1").unwrap()).await; - dns_manager.del_domain(&"test000".to_string()).await; + _ = dns_manager + .add_domain( + &"testzone".to_string(), + Ipv4Addr::from_str("1.1.1.1").unwrap(), + ) + .await; + _ = dns_manager.del_domain(&"testzone".to_string()).await; }