use std::sync::Arc;
use tracing::debug;
use crate::{
authority::{Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType},
proto::rr::{LowerName, Record, RecordType},
server::RequestInfo,
};
#[async_trait::async_trait]
pub trait AuthorityObject: Send + Sync {
fn box_clone(&self) -> Box<dyn AuthorityObject>;
fn zone_type(&self) -> ZoneType;
fn is_axfr_allowed(&self) -> bool;
async fn update(&self, update: &MessageRequest) -> UpdateResult<bool>;
fn origin(&self) -> &LowerName;
async fn lookup(
&self,
name: &LowerName,
rtype: RecordType,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError>;
async fn search(
&self,
request_info: RequestInfo<'_>,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError>;
async fn ns(
&self,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError> {
self.lookup(self.origin(), RecordType::NS, lookup_options)
.await
}
async fn get_nsec_records(
&self,
name: &LowerName,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError>;
async fn soa(&self) -> Result<Box<dyn LookupObject>, LookupError> {
self.lookup(self.origin(), RecordType::SOA, LookupOptions::default())
.await
}
async fn soa_secure(
&self,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError> {
self.lookup(self.origin(), RecordType::SOA, lookup_options)
.await
}
}
#[async_trait::async_trait]
impl<A, L> AuthorityObject for Arc<A>
where
A: Authority<Lookup = L> + Send + Sync + 'static,
L: LookupObject + Send + Sync + 'static,
{
fn box_clone(&self) -> Box<dyn AuthorityObject> {
Box::new(self.clone())
}
fn zone_type(&self) -> ZoneType {
Authority::zone_type(self.as_ref())
}
fn is_axfr_allowed(&self) -> bool {
Authority::is_axfr_allowed(self.as_ref())
}
async fn update(&self, update: &MessageRequest) -> UpdateResult<bool> {
Authority::update(self.as_ref(), update).await
}
fn origin(&self) -> &LowerName {
Authority::origin(self.as_ref())
}
async fn lookup(
&self,
name: &LowerName,
rtype: RecordType,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError> {
let this = self.as_ref();
let lookup = Authority::lookup(this, name, rtype, lookup_options).await;
lookup.map(|l| Box::new(l) as Box<dyn LookupObject>)
}
async fn search(
&self,
request_info: RequestInfo<'_>,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError> {
let this = self.as_ref();
debug!("performing {} on {}", request_info.query, this.origin());
let lookup = Authority::search(this, request_info, lookup_options).await;
lookup.map(|l| Box::new(l) as Box<dyn LookupObject>)
}
async fn get_nsec_records(
&self,
name: &LowerName,
lookup_options: LookupOptions,
) -> Result<Box<dyn LookupObject>, LookupError> {
let lookup = Authority::get_nsec_records(self.as_ref(), name, lookup_options).await;
lookup.map(|l| Box::new(l) as Box<dyn LookupObject>)
}
}
pub trait LookupObject: Send {
fn is_empty(&self) -> bool;
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a>;
fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>>;
}
#[derive(Clone, Copy, Debug)]
pub struct EmptyLookup;
impl LookupObject for EmptyLookup {
fn is_empty(&self) -> bool {
true
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a> {
Box::new([].iter())
}
fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>> {
None
}
}