From a6bec0fa6f5ba64131409c8145faa0516a32214f Mon Sep 17 00:00:00 2001 From: Luna Yao <40349250+ZnqbuZ@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:26:13 +0100 Subject: [PATCH] zone: move chained authority to utils, rewrite authority creation --- easytier/src/dns/utils.rs | 92 ++++++++++++++++++++++- easytier/src/dns/zone.rs | 154 ++++++++++---------------------------- 2 files changed, 129 insertions(+), 117 deletions(-) diff --git a/easytier/src/dns/utils.rs b/easytier/src/dns/utils.rs index 621be164..c7c7060b 100644 --- a/easytier/src/dns/utils.rs +++ b/easytier/src/dns/utils.rs @@ -1,7 +1,13 @@ use anyhow::{anyhow, Error}; -use hickory_proto::rr::LowerName; +use derive_more::{Deref, DerefMut}; +use hickory_proto::rr::{LowerName, RecordType}; use hickory_proto::xfer::Protocol; use hickory_resolver::config::NameServerConfig; +use hickory_server::authority::{ + Authority, LookupControlFlow, LookupObject, LookupOptions, MessageRequest, UpdateResult, + ZoneType, +}; +use hickory_server::server::RequestInfo; use idna::AsciiDenyList; use serde_with::{DeserializeFromStr, SerializeDisplay}; use std::fmt::{Display, Formatter}; @@ -121,3 +127,87 @@ impl Display for NameServerAddr { f.write_str(Url::from(self).as_str()) } } + +#[derive(Deref, DerefMut)] +pub struct ChainedAuthority(pub(super) A) +where + A: Authority, + A::Lookup: LookupObject + 'static; + +impl From for ChainedAuthority +where + A: Authority, + A::Lookup: LookupObject + 'static, +{ + fn from(value: A) -> Self { + Self(value) + } +} + +#[async_trait::async_trait] +impl Authority for ChainedAuthority +where + A: Authority, + A::Lookup: LookupObject + 'static, +{ + type Lookup = A::Lookup; + + #[inline] + fn zone_type(&self) -> ZoneType { + self.0.zone_type() + } + #[inline] + fn is_axfr_allowed(&self) -> bool { + self.0.is_axfr_allowed() + } + #[inline] + async fn update(&self, update: &MessageRequest) -> UpdateResult { + self.0.update(update).await + } + #[inline] + fn origin(&self) -> &LowerName { + self.0.origin() + } + #[inline] + async fn lookup( + &self, + name: &LowerName, + rtype: RecordType, + lookup_options: LookupOptions, + ) -> LookupControlFlow { + self.0.lookup(name, rtype, lookup_options).await + } + #[inline] + async fn consult( + &self, + name: &LowerName, + rtype: RecordType, + lookup_options: LookupOptions, + last_result: LookupControlFlow>, + ) -> LookupControlFlow> { + if let Some(Ok(l)) = last_result.map_result() { + LookupControlFlow::Break(Ok(l)) + } else { + self.0 + .lookup(name, rtype, lookup_options) + .await + .map(|l| Box::new(l) as _) + } + } + #[inline] + async fn search( + &self, + request_info: RequestInfo<'_>, + lookup_options: LookupOptions, + ) -> LookupControlFlow { + self.0.search(request_info, lookup_options).await + } + #[inline] + async fn get_nsec_records( + &self, + name: &LowerName, + lookup_options: LookupOptions, + ) -> LookupControlFlow { + self.0.get_nsec_records(name, lookup_options).await + } +} diff --git a/easytier/src/dns/zone.rs b/easytier/src/dns/zone.rs index ed91a517..378a60c0 100644 --- a/easytier/src/dns/zone.rs +++ b/easytier/src/dns/zone.rs @@ -1,104 +1,15 @@ -use crate::dns::utils::NameServerAddr; +use crate::dns::utils::{ChainedAuthority, NameServerAddr}; use crate::proto::dns::ZoneConfigPb; -use async_trait::async_trait; -use derive_more::{Deref, DerefMut}; -use hickory_proto::rr::{LowerName, Record, RecordSet, RecordType, RrKey, RrsetRecords}; +use hickory_proto::rr::{LowerName, Record, RecordSet, RrKey, RrsetRecords}; use hickory_proto::serialize::txt::Parser; -use hickory_proto::xfer::Protocol; -use hickory_resolver::config::{NameServerConfig, ResolverOpts}; +use hickory_resolver::config::ResolverOpts; use hickory_resolver::name_server::TokioConnectionProvider; -use hickory_server::authority::{ - Authority, AuthorityObject, LookupControlFlow, LookupObject, LookupOptions, MessageRequest, - UpdateResult, ZoneType, -}; -use hickory_server::server::RequestInfo; +use hickory_server::authority::ZoneType; use hickory_server::store::forwarder::{ForwardAuthority, ForwardConfig}; use hickory_server::store::in_memory::InMemoryAuthority; use std::collections::BTreeMap; -use std::mem; -use std::net::{IpAddr, SocketAddr}; use std::str::FromStr; use std::sync::Arc; -use url::Url; - -#[derive(Deref, DerefMut)] -pub struct FallbackAuthority -where - A: Authority + Send + Sync + 'static, - L: LookupObject + Send + Sync + 'static, -{ - #[deref] - #[deref_mut] - inner: A, -} - -#[async_trait] -impl Authority for FallbackAuthority -where - A: Authority + Send + Sync + 'static, - L: LookupObject + Send + Sync + 'static, -{ - type Lookup = L; - - #[inline] - fn zone_type(&self) -> ZoneType { - self.inner.zone_type() - } - #[inline] - fn is_axfr_allowed(&self) -> bool { - self.inner.is_axfr_allowed() - } - #[inline] - async fn update(&self, update: &MessageRequest) -> UpdateResult { - self.inner.update(update).await - } - #[inline] - fn origin(&self) -> &LowerName { - self.inner.origin() - } - #[inline] - async fn lookup( - &self, - name: &LowerName, - rtype: RecordType, - lookup_options: LookupOptions, - ) -> LookupControlFlow { - self.inner.lookup(name, rtype, lookup_options).await - } - #[inline] - async fn consult( - &self, - name: &LowerName, - rtype: RecordType, - lookup_options: LookupOptions, - last_result: LookupControlFlow>, - ) -> LookupControlFlow> { - if let Some(Ok(l)) = last_result.map_result() { - LookupControlFlow::Break(Ok(l)) - } else { - self.inner - .lookup(name, rtype, lookup_options) - .await - .map(|l| Box::new(l) as _) - } - } - #[inline] - async fn search( - &self, - request_info: RequestInfo<'_>, - lookup_options: LookupOptions, - ) -> LookupControlFlow { - self.inner.search(request_info, lookup_options).await - } - #[inline] - async fn get_nsec_records( - &self, - name: &LowerName, - lookup_options: LookupOptions, - ) -> LookupControlFlow { - self.inner.get_nsec_records(name, lookup_options).await - } -} #[derive(Debug, Clone)] pub struct Zone { @@ -116,34 +27,35 @@ impl Zone { } } - pub fn create_authorities(&self) -> anyhow::Result>> { - let mut authorities = Vec::>::with_capacity(2); + pub fn create_memory_authority(&self) -> Option>> { + (!self.records.is_empty()).then(|| { + let mut memory = + InMemoryAuthority::empty(self.origin.clone().into(), ZoneType::External, false); - let mut memory = - InMemoryAuthority::empty(self.origin.clone().into(), ZoneType::External, false); + memory.records_get_mut().extend( + self.records + .clone() + .into_iter() + .map(|(k, v)| (k, Arc::new(v))), + ); - let mut records = self - .records - .clone() - .into_iter() - .map(|(k, v)| (k, Arc::new(v))) - .collect(); - mem::swap(memory.records_get_mut(), &mut records); + Arc::new(memory.into()) + }) + } - authorities.push(Arc::new(memory)); - - if let Some(forward) = &self.forward { - let forward = ForwardAuthority::builder_with_config( + pub fn create_forward_authority( + &self, + ) -> Option>>> { + self.forward.as_ref().and_then(|forward| { + ForwardAuthority::builder_with_config( forward.clone(), TokioConnectionProvider::default(), ) .build() - .map_err(|e| anyhow::anyhow!("failed to create forward authority: {}", e))?; - let forward = FallbackAuthority { inner: forward }; - authorities.push(Arc::new(forward)); - } - - Ok(authorities) + .inspect_err(|e| tracing::error!("failed to create forward authority: {:?}", e)) + .ok() + .map(|f| Arc::new(f.into())) + }) } pub fn set_forwarders( @@ -215,7 +127,7 @@ mod tests { use hickory_proto::rr::{rdata, DNSClass, Name, RData, RecordType}; use hickory_proto::runtime::TokioRuntimeProvider; use hickory_proto::udp::UdpClientStream; - use hickory_server::authority::Catalog; + use hickory_server::authority::{AuthorityObject, Catalog}; use hickory_server::ServerFuture; use std::time::Duration; use tokio::net::UdpSocket; @@ -334,7 +246,17 @@ mod tests { assert_eq!(zone.forward.as_ref().unwrap().name_servers.len(), 1); - let authorities = zone.create_authorities()?; + let mut authorities = Vec::new(); + authorities.extend( + zone.create_memory_authority() + .map(|a| a as Arc) + .into_iter(), + ); + authorities.extend( + zone.create_forward_authority() + .map(|a| a as Arc) + .into_iter(), + ); assert_eq!(authorities.len(), 2); let mut catalog = Catalog::new(); catalog.upsert(zone.origin.clone().into(), authorities);