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);