Move to async-trait for server to simplify function calls
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1676,6 +1676,7 @@ dependencies = [
|
||||
name = "trust-dns-integration"
|
||||
version = "0.21.0-alpha.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"env_logger",
|
||||
"futures",
|
||||
|
@@ -40,46 +40,48 @@ extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
use std::future::Future;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, ToSocketAddrs},
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use clap::{Arg, ArgMatches};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::runtime::{self, Runtime};
|
||||
use futures::lock::Mutex;
|
||||
use tokio::{
|
||||
net::{TcpListener, UdpSocket},
|
||||
runtime::{self, Runtime},
|
||||
};
|
||||
|
||||
use trust_dns_client::rr::Name;
|
||||
use trust_dns_server::authority::{AuthorityObject, Catalog, ZoneType};
|
||||
#[cfg(feature = "dns-over-tls")]
|
||||
use trust_dns_server::config::dnssec::{self, TlsCertConfig};
|
||||
use trust_dns_server::config::{Config, ZoneConfig};
|
||||
use trust_dns_server::logger;
|
||||
use trust_dns_server::server::ServerFuture;
|
||||
use trust_dns_server::store::file::{FileAuthority, FileConfig};
|
||||
#[cfg(feature = "resolver")]
|
||||
use trust_dns_server::store::forwarder::ForwardAuthority;
|
||||
#[cfg(feature = "sqlite")]
|
||||
use trust_dns_server::store::sqlite::{SqliteAuthority, SqliteConfig};
|
||||
use trust_dns_server::store::StoreConfig;
|
||||
#[cfg(feature = "dnssec")]
|
||||
use {
|
||||
trust_dns_client::rr::rdata::key::KeyUsage, trust_dns_server::authority::DnssecAuthority,
|
||||
trust_dns_server::authority::LookupError,
|
||||
use trust_dns_server::{
|
||||
authority::{AuthorityObject, Catalog, ZoneType},
|
||||
config::{Config, ZoneConfig},
|
||||
store::{
|
||||
file::{FileAuthority, FileConfig},
|
||||
StoreConfig,
|
||||
},
|
||||
};
|
||||
use trust_dns_server::{logger, server::ServerFuture};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
fn load_keys<A, L, LF>(
|
||||
use {trust_dns_client::rr::rdata::key::KeyUsage, trust_dns_server::authority::DnssecAuthority};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
fn load_keys<A, L>(
|
||||
authority: &mut A,
|
||||
zone_name: Name,
|
||||
zone_config: &ZoneConfig,
|
||||
) -> Result<(), String>
|
||||
where
|
||||
A: DnssecAuthority<Lookup = L, LookupFuture = LF>,
|
||||
A: DnssecAuthority<Lookup = L>,
|
||||
L: Send + Sized + 'static,
|
||||
LF: Future<Output = Result<L, LookupError>> + Send,
|
||||
{
|
||||
if zone_config.is_dnssec_enabled() {
|
||||
for key_config in zone_config.get_keys() {
|
||||
@@ -168,7 +170,7 @@ fn load_zone(
|
||||
|
||||
// load any keys for the Zone, if it is a dynamic update zone, then keys are required
|
||||
load_keys(&mut authority, zone_name_for_signer, zone_config)?;
|
||||
Box::new(Arc::new(RwLock::new(authority)))
|
||||
Box::new(Arc::new(Mutex::new(authority)))
|
||||
}
|
||||
Some(StoreConfig::File(ref config)) => {
|
||||
if zone_path.is_some() {
|
||||
@@ -185,14 +187,14 @@ fn load_zone(
|
||||
|
||||
// load any keys for the Zone, if it is a dynamic update zone, then keys are required
|
||||
load_keys(&mut authority, zone_name_for_signer, zone_config)?;
|
||||
Box::new(Arc::new(RwLock::new(authority)))
|
||||
Box::new(Arc::new(Mutex::new(authority)))
|
||||
}
|
||||
#[cfg(feature = "resolver")]
|
||||
Some(StoreConfig::Forward(ref config)) => {
|
||||
let forwarder = ForwardAuthority::try_from_config(zone_name, zone_type, config);
|
||||
let authority = runtime.block_on(forwarder)?;
|
||||
|
||||
Box::new(Arc::new(RwLock::new(authority)))
|
||||
Box::new(Arc::new(Mutex::new(authority)))
|
||||
}
|
||||
#[cfg(feature = "sqlite")]
|
||||
None if zone_config.is_update_allowed() => {
|
||||
@@ -223,7 +225,7 @@ fn load_zone(
|
||||
|
||||
// load any keys for the Zone, if it is a dynamic update zone, then keys are required
|
||||
load_keys(&mut authority, zone_name_for_signer, zone_config)?;
|
||||
Box::new(Arc::new(RwLock::new(authority)))
|
||||
Box::new(Arc::new(Mutex::new(authority)))
|
||||
}
|
||||
None => {
|
||||
let config = FileConfig {
|
||||
@@ -240,7 +242,7 @@ fn load_zone(
|
||||
|
||||
// load any keys for the Zone, if it is a dynamic update zone, then keys are required
|
||||
load_keys(&mut authority, zone_name_for_signer, zone_config)?;
|
||||
Box::new(Arc::new(RwLock::new(authority)))
|
||||
Box::new(Arc::new(Mutex::new(authority)))
|
||||
}
|
||||
Some(_) => {
|
||||
panic!("unrecognized authority type, check enabled features");
|
||||
|
@@ -65,7 +65,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
async-std = "1.6"
|
||||
async-trait = "0.1.36"
|
||||
async-trait = "0.1.42"
|
||||
futures-io = { version = "0.3.5", default-features = false, features = ["std"] }
|
||||
futures-util = { version = "0.3.5", default-features = false, features = ["std"] }
|
||||
pin-utils = "0.1.0"
|
||||
|
@@ -68,7 +68,7 @@ name = "trust_dns_proto"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.36"
|
||||
async-trait = "0.1.42"
|
||||
backtrace = { version = "0.3.50", optional = true }
|
||||
bytes = { version = "1", optional = true }
|
||||
cfg-if = "1"
|
||||
|
@@ -6,21 +6,23 @@
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
//! All authority related types
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
use crate::authority::{LookupError, MessageRequest, UpdateResult, ZoneType};
|
||||
use crate::client::op::LowerQuery;
|
||||
use crate::client::rr::{LowerName, RecordSet, RecordType};
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::client::{
|
||||
proto::rr::dnssec::rdata::key::KEY,
|
||||
rr::dnssec::{DnsSecResult, SigSigner, SupportedAlgorithms},
|
||||
rr::Name,
|
||||
};
|
||||
use crate::proto::rr::RrsetRecords;
|
||||
use crate::{
|
||||
authority::{LookupError, MessageRequest, UpdateResult, ZoneType},
|
||||
client::{
|
||||
op::LowerQuery,
|
||||
rr::{LowerName, RecordSet, RecordType},
|
||||
},
|
||||
proto::rr::RrsetRecords,
|
||||
};
|
||||
|
||||
/// LookupOptions that specify different options from the client to include or exclude various records in the response.
|
||||
///
|
||||
@@ -95,11 +97,10 @@ impl LookupOptions {
|
||||
}
|
||||
|
||||
/// Authority implementations can be used with a `Catalog`
|
||||
pub trait Authority: Send {
|
||||
#[async_trait::async_trait]
|
||||
pub trait Authority: Send + Sync {
|
||||
/// Result of a lookup
|
||||
type Lookup: Send + Sized + 'static;
|
||||
/// The future type that will resolve to a Lookup
|
||||
type LookupFuture: Future<Output = Result<Self::Lookup, LookupError>> + Send;
|
||||
type Lookup: Send + Sync + Sized + 'static;
|
||||
|
||||
/// What type is this zone
|
||||
fn zone_type(&self) -> ZoneType;
|
||||
@@ -108,7 +109,7 @@ pub trait Authority: Send {
|
||||
fn is_axfr_allowed(&self) -> bool;
|
||||
|
||||
/// Perform a dynamic update of a zone
|
||||
fn update(&mut self, update: &MessageRequest) -> UpdateResult<bool>;
|
||||
async fn update(&mut self, update: &MessageRequest) -> UpdateResult<bool>;
|
||||
|
||||
/// Get the origin of this zone, i.e. example.com is the origin for www.example.com
|
||||
fn origin(&self) -> &LowerName;
|
||||
@@ -127,12 +128,12 @@ pub trait Authority: Send {
|
||||
/// # Return value
|
||||
///
|
||||
/// None if there are no matching records, otherwise a `Vec` containing the found records.
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
rtype: RecordType,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>>;
|
||||
) -> Result<Self::Lookup, LookupError>;
|
||||
|
||||
/// Using the specified query, perform a lookup against this zone.
|
||||
///
|
||||
@@ -145,18 +146,16 @@ pub trait Authority: Send {
|
||||
///
|
||||
/// Returns a vectory containing the results of the query, it will be empty if not found. If
|
||||
/// `is_secure` is true, in the case of no records found then NSEC records will be returned.
|
||||
fn search(
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>>;
|
||||
) -> Result<Self::Lookup, LookupError>;
|
||||
|
||||
/// Get the NS, NameServer, record for the zone
|
||||
fn ns(
|
||||
&self,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
async fn ns(&self, lookup_options: LookupOptions) -> Result<Self::Lookup, LookupError> {
|
||||
self.lookup(self.origin(), RecordType::NS, lookup_options)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Return the NSEC records based on the given name
|
||||
@@ -166,27 +165,26 @@ pub trait Authority: Send {
|
||||
/// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
|
||||
/// this
|
||||
/// * `is_secure` - if true then it will return RRSIG records as well
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>>;
|
||||
) -> Result<Self::Lookup, LookupError>;
|
||||
|
||||
/// Returns the SOA of the authority.
|
||||
///
|
||||
/// *Note*: This will only return the SOA, if this is fulfilling a request, a standard lookup
|
||||
/// should be used, see `soa_secure()`, which will optionally return RRSIGs.
|
||||
fn soa(&self) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
async fn soa(&self) -> Result<Self::Lookup, LookupError> {
|
||||
// SOA should be origin|SOA
|
||||
self.lookup(self.origin(), RecordType::SOA, LookupOptions::default())
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns the SOA record for the zone
|
||||
fn soa_secure(
|
||||
&self,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
async fn soa_secure(&self, lookup_options: LookupOptions) -> Result<Self::Lookup, LookupError> {
|
||||
self.lookup(self.origin(), RecordType::SOA, lookup_options)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
@@ -7,36 +7,36 @@
|
||||
|
||||
//! All authority related types
|
||||
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::task::{Context, Poll};
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures_util::{future, TryFutureExt};
|
||||
use futures_util::lock::Mutex;
|
||||
use log::debug;
|
||||
|
||||
use crate::authority::{
|
||||
Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType,
|
||||
use crate::{
|
||||
authority::{Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType},
|
||||
client::{
|
||||
op::LowerQuery,
|
||||
rr::{LowerName, Record, RecordType},
|
||||
},
|
||||
};
|
||||
use crate::client::op::LowerQuery;
|
||||
use crate::client::rr::{LowerName, Record, RecordType};
|
||||
|
||||
/// An Object safe Authority
|
||||
#[async_trait::async_trait]
|
||||
pub trait AuthorityObject: Send + Sync {
|
||||
/// Clone the object
|
||||
fn box_clone(&self) -> Box<dyn AuthorityObject>;
|
||||
|
||||
/// What type is this zone
|
||||
fn zone_type(&self) -> ZoneType;
|
||||
async fn zone_type(&self) -> ZoneType;
|
||||
|
||||
/// Return true if AXFR is allowed
|
||||
fn is_axfr_allowed(&self) -> bool;
|
||||
async fn is_axfr_allowed(&self) -> bool;
|
||||
|
||||
/// Perform a dynamic update of a zone
|
||||
fn update(&self, update: &MessageRequest) -> UpdateResult<bool>;
|
||||
async fn update(&self, update: &MessageRequest) -> UpdateResult<bool>;
|
||||
|
||||
/// Get the origin of this zone, i.e. example.com is the origin for www.example.com
|
||||
fn origin(&self) -> LowerName;
|
||||
async fn origin(&self) -> LowerName;
|
||||
|
||||
/// Looks up all Resource Records matching the giving `Name` and `RecordType`.
|
||||
///
|
||||
@@ -52,12 +52,12 @@ pub trait AuthorityObject: Send + Sync {
|
||||
/// # Return value
|
||||
///
|
||||
/// None if there are no matching records, otherwise a `Vec` containing the found records.
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
rtype: RecordType,
|
||||
lookup_options: LookupOptions,
|
||||
) -> BoxedLookupFuture;
|
||||
) -> Result<Box<dyn LookupObject>, LookupError>;
|
||||
|
||||
/// Using the specified query, perform a lookup against this zone.
|
||||
///
|
||||
@@ -70,11 +70,19 @@ pub trait AuthorityObject: Send + Sync {
|
||||
///
|
||||
/// Returns a vectory containing the results of the query, it will be empty if not found. If
|
||||
/// `is_secure` is true, in the case of no records found then NSEC records will be returned.
|
||||
fn search(&self, query: &LowerQuery, lookup_options: LookupOptions) -> BoxedLookupFuture;
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Result<Box<dyn LookupObject>, LookupError>;
|
||||
|
||||
/// Get the NS, NameServer, record for the zone
|
||||
fn ns(&self, lookup_options: LookupOptions) -> BoxedLookupFuture {
|
||||
self.lookup(&self.origin(), RecordType::NS, lookup_options)
|
||||
async fn ns(
|
||||
&self,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Result<Box<dyn LookupObject>, LookupError> {
|
||||
self.lookup(&self.origin().await, RecordType::NS, lookup_options)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Return the NSEC records based on the given name
|
||||
@@ -84,55 +92,64 @@ pub trait AuthorityObject: Send + Sync {
|
||||
/// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
|
||||
/// this
|
||||
/// * `is_secure` - if true then it will return RRSIG records as well
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> BoxedLookupFuture;
|
||||
) -> Result<Box<dyn LookupObject>, LookupError>;
|
||||
|
||||
/// Returns the SOA of the authority.
|
||||
///
|
||||
/// *Note*: This will only return the SOA, if this is fulfilling a request, a standard lookup
|
||||
/// should be used, see `soa_secure()`, which will optionally return RRSIGs.
|
||||
fn soa(&self) -> BoxedLookupFuture {
|
||||
async fn soa(&self) -> Result<Box<dyn LookupObject>, LookupError> {
|
||||
// SOA should be origin|SOA
|
||||
self.lookup(&self.origin(), RecordType::SOA, LookupOptions::default())
|
||||
self.lookup(
|
||||
&self.origin().await,
|
||||
RecordType::SOA,
|
||||
LookupOptions::default(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns the SOA record for the zone
|
||||
fn soa_secure(&self, lookup_options: LookupOptions) -> BoxedLookupFuture {
|
||||
self.lookup(&self.origin(), RecordType::SOA, lookup_options)
|
||||
async fn soa_secure(
|
||||
&self,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Result<Box<dyn LookupObject>, LookupError> {
|
||||
self.lookup(&self.origin().await, RecordType::SOA, lookup_options)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, L> AuthorityObject for Arc<RwLock<A>>
|
||||
#[async_trait::async_trait]
|
||||
impl<A, L> AuthorityObject for Arc<Mutex<A>>
|
||||
where
|
||||
A: Authority<Lookup = L> + Send + Sync + 'static,
|
||||
A::LookupFuture: Send + 'static,
|
||||
L: LookupObject + Send + 'static,
|
||||
L: LookupObject + Send + Sync + 'static,
|
||||
{
|
||||
fn box_clone(&self) -> Box<dyn AuthorityObject> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
/// What type is this zone
|
||||
fn zone_type(&self) -> ZoneType {
|
||||
Authority::zone_type(&*self.read().expect("poisoned"))
|
||||
async fn zone_type(&self) -> ZoneType {
|
||||
Authority::zone_type(&*self.lock().await)
|
||||
}
|
||||
|
||||
/// Return true if AXFR is allowed
|
||||
fn is_axfr_allowed(&self) -> bool {
|
||||
Authority::is_axfr_allowed(&*self.read().expect("poisoned"))
|
||||
async fn is_axfr_allowed(&self) -> bool {
|
||||
Authority::is_axfr_allowed(&*self.lock().await)
|
||||
}
|
||||
|
||||
/// Perform a dynamic update of a zone
|
||||
fn update(&self, update: &MessageRequest) -> UpdateResult<bool> {
|
||||
Authority::update(&mut *self.write().expect("poisoned"), update)
|
||||
async fn update(&self, update: &MessageRequest) -> UpdateResult<bool> {
|
||||
Authority::update(&mut *self.lock().await, update).await
|
||||
}
|
||||
|
||||
/// Get the origin of this zone, i.e. example.com is the origin for www.example.com
|
||||
fn origin(&self) -> LowerName {
|
||||
Authority::origin(&*self.read().expect("poisoned")).clone()
|
||||
async fn origin(&self) -> LowerName {
|
||||
Authority::origin(&*self.lock().await).clone()
|
||||
}
|
||||
|
||||
/// Looks up all Resource Records matching the giving `Name` and `RecordType`.
|
||||
@@ -149,15 +166,15 @@ where
|
||||
/// # Return value
|
||||
///
|
||||
/// None if there are no matching records, otherwise a `Vec` containing the found records.
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
rtype: RecordType,
|
||||
lookup_options: LookupOptions,
|
||||
) -> BoxedLookupFuture {
|
||||
let this = self.read().expect("poisoned");
|
||||
let lookup = Authority::lookup(&*this, name, rtype, lookup_options);
|
||||
BoxedLookupFuture::from(lookup.map_ok(|l| Box::new(l) as Box<dyn LookupObject>))
|
||||
) -> Result<Box<dyn LookupObject>, LookupError> {
|
||||
let this = self.lock().await;
|
||||
let lookup = Authority::lookup(&*this, name, rtype, lookup_options).await;
|
||||
lookup.map(|l| Box::new(l) as Box<dyn LookupObject>)
|
||||
}
|
||||
|
||||
/// Using the specified query, perform a lookup against this zone.
|
||||
@@ -171,11 +188,15 @@ where
|
||||
///
|
||||
/// Returns a vectory containing the results of the query, it will be empty if not found. If
|
||||
/// `is_secure` is true, in the case of no records found then NSEC records will be returned.
|
||||
fn search(&self, query: &LowerQuery, lookup_options: LookupOptions) -> BoxedLookupFuture {
|
||||
let this = self.read().expect("poisoned");
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Result<Box<dyn LookupObject>, LookupError> {
|
||||
let this = self.lock().await;
|
||||
debug!("performing {} on {}", query, this.origin());
|
||||
let lookup = Authority::search(&*this, query, lookup_options);
|
||||
BoxedLookupFuture::from(lookup.map_ok(|l| Box::new(l) as Box<dyn LookupObject>))
|
||||
let lookup = Authority::search(&*this, query, lookup_options).await;
|
||||
lookup.map(|l| Box::new(l) as Box<dyn LookupObject>)
|
||||
}
|
||||
|
||||
/// Return the NSEC records based on the given name
|
||||
@@ -185,14 +206,13 @@ where
|
||||
/// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
|
||||
/// this
|
||||
/// * `is_secure` - if true then it will return RRSIG records as well
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> BoxedLookupFuture {
|
||||
let lookup =
|
||||
Authority::get_nsec_records(&*self.read().expect("poisoned"), name, lookup_options);
|
||||
BoxedLookupFuture::from(lookup.map_ok(|l| Box::new(l) as Box<dyn LookupObject>))
|
||||
) -> Result<Box<dyn LookupObject>, LookupError> {
|
||||
let lookup = Authority::get_nsec_records(&*self.lock().await, name, lookup_options).await;
|
||||
lookup.map(|l| Box::new(l) as Box<dyn LookupObject>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,34 +247,3 @@ impl LookupObject for EmptyLookup {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A boxed lookup future
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct BoxedLookupFuture(
|
||||
Pin<Box<dyn Future<Output = Result<Box<dyn LookupObject>, LookupError>> + Send>>,
|
||||
);
|
||||
|
||||
impl BoxedLookupFuture {
|
||||
/// Performs a conversion (boxes) into the future
|
||||
pub fn from<T>(future: T) -> Self
|
||||
where
|
||||
T: Future<Output = Result<Box<dyn LookupObject>, LookupError>> + Send + Sized + 'static,
|
||||
{
|
||||
BoxedLookupFuture(Box::pin(future))
|
||||
}
|
||||
|
||||
/// Creates an empty (i.e. no records) lookup future
|
||||
pub fn empty() -> Self {
|
||||
BoxedLookupFuture(Box::pin(future::ok(
|
||||
Box::new(EmptyLookup) as Box<dyn LookupObject>
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for BoxedLookupFuture {
|
||||
type Output = Result<Box<dyn LookupObject>, LookupError>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
self.0.as_mut().poll(cx)
|
||||
}
|
||||
}
|
||||
|
@@ -8,29 +8,27 @@
|
||||
// TODO, I've implemented this as a separate entity from the cache, but I wonder if the cache
|
||||
// should be the only "front-end" for lookups, where if that misses, then we go to the catalog
|
||||
// then, if requested, do a recursive lookup... i.e. the catalog would only point to files.
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::{borrow::Borrow, collections::HashMap, future::Future, io};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use crate::authority::{
|
||||
AuthLookup, MessageRequest, MessageResponse, MessageResponseBuilder, ZoneType,
|
||||
};
|
||||
use crate::authority::{
|
||||
AuthorityObject, BoxedLookupFuture, EmptyLookup, LookupError, LookupObject, LookupOptions,
|
||||
};
|
||||
use crate::client::op::{Edns, Header, LowerQuery, MessageType, OpCode, ResponseCode};
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::client::rr::{
|
||||
dnssec::{Algorithm, SupportedAlgorithms},
|
||||
rdata::opt::{EdnsCode, EdnsOption},
|
||||
};
|
||||
use crate::client::rr::{LowerName, RecordType};
|
||||
use crate::server::{Request, RequestHandler, ResponseHandler};
|
||||
use crate::{
|
||||
authority::{
|
||||
AuthLookup, AuthorityObject, EmptyLookup, LookupError, LookupObject, LookupOptions,
|
||||
MessageRequest, MessageResponse, MessageResponseBuilder, ZoneType,
|
||||
},
|
||||
client::{
|
||||
op::{Edns, Header, LowerQuery, MessageType, OpCode, ResponseCode},
|
||||
rr::{LowerName, RecordType},
|
||||
},
|
||||
server::{Request, RequestHandler, ResponseHandler},
|
||||
};
|
||||
|
||||
/// Set of authorities, zones, available to this server.
|
||||
#[derive(Default)]
|
||||
@@ -39,7 +37,7 @@ pub struct Catalog {
|
||||
}
|
||||
|
||||
#[allow(unused_mut, unused_variables)]
|
||||
fn send_response<R: ResponseHandler>(
|
||||
async fn send_response<R: ResponseHandler>(
|
||||
response_edns: Option<Edns>,
|
||||
mut response: MessageResponse<'_, '_>,
|
||||
mut response_handle: R,
|
||||
@@ -63,23 +61,18 @@ fn send_response<R: ResponseHandler>(
|
||||
response.set_edns(resp_edns);
|
||||
}
|
||||
|
||||
response_handle.send_response(response)
|
||||
response_handle.send_response(response).await
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RequestHandler for Catalog {
|
||||
type ResponseFuture = Pin<Box<dyn Future<Output = ()> + Send>>;
|
||||
|
||||
/// Determines what needs to happen given the type of request, i.e. Query or Update.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `request` - the requested action to perform.
|
||||
/// * `response_handle` - sink for the response message to be sent
|
||||
fn handle_request<R: ResponseHandler>(
|
||||
&self,
|
||||
request: Request,
|
||||
mut response_handle: R,
|
||||
) -> Self::ResponseFuture {
|
||||
async fn handle_request<R: ResponseHandler>(&self, request: Request, mut response_handle: R) {
|
||||
let request_message = request.message;
|
||||
trace!("request: {:?}", request_message);
|
||||
|
||||
@@ -109,12 +102,13 @@ impl RequestHandler for Catalog {
|
||||
response.edns(resp_edns);
|
||||
|
||||
// TODO: should ResponseHandle consume self?
|
||||
let result =
|
||||
response_handle.send_response(response.build_no_records(response_header));
|
||||
let result = response_handle
|
||||
.send_response(response.build_no_records(response_header))
|
||||
.await;
|
||||
if let Err(e) = result {
|
||||
error!("request error: {}", e);
|
||||
}
|
||||
return Box::pin(async {});
|
||||
return;
|
||||
}
|
||||
|
||||
response_edns = Some(resp_edns);
|
||||
@@ -128,19 +122,24 @@ impl RequestHandler for Catalog {
|
||||
MessageType::Query => match request_message.op_code() {
|
||||
OpCode::Query => {
|
||||
debug!("query received: {}", request_message.id());
|
||||
return Box::pin(self.lookup(request_message, response_edns, response_handle));
|
||||
self.lookup(request_message, response_edns, response_handle)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
OpCode::Update => {
|
||||
debug!("update received: {}", request_message.id());
|
||||
// TODO: this should be a future
|
||||
self.update(&request_message, response_edns, response_handle)
|
||||
.await
|
||||
}
|
||||
c => {
|
||||
warn!("unimplemented op_code: {:?}", c);
|
||||
let response = MessageResponseBuilder::new(Some(request_message.raw_queries()));
|
||||
response_handle.send_response(
|
||||
response.error_msg(request_message.header(), ResponseCode::NotImp),
|
||||
)
|
||||
response_handle
|
||||
.send_response(
|
||||
response.error_msg(request_message.header(), ResponseCode::NotImp),
|
||||
)
|
||||
.await
|
||||
}
|
||||
},
|
||||
MessageType::Response => {
|
||||
@@ -149,16 +148,17 @@ impl RequestHandler for Catalog {
|
||||
request_message.id()
|
||||
);
|
||||
let response = MessageResponseBuilder::new(Some(request_message.raw_queries()));
|
||||
response_handle.send_response(
|
||||
response.error_msg(request_message.header(), ResponseCode::FormErr),
|
||||
)
|
||||
response_handle
|
||||
.send_response(
|
||||
response.error_msg(request_message.header(), ResponseCode::FormErr),
|
||||
)
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = result {
|
||||
error!("request failed: {}", e);
|
||||
}
|
||||
Box::pin(async {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ impl Catalog {
|
||||
///
|
||||
/// * `request` - an update message
|
||||
/// * `response_handle` - sink for the response message to be sent
|
||||
pub fn update<R: ResponseHandler + 'static>(
|
||||
pub async fn update<R: ResponseHandler + 'static>(
|
||||
&self,
|
||||
update: &MessageRequest,
|
||||
response_edns: Option<Edns>,
|
||||
@@ -270,23 +270,14 @@ impl Catalog {
|
||||
|
||||
let response_code = match result {
|
||||
Ok(authority) => {
|
||||
// Ask for Master/Slave terms to be replaced
|
||||
#[allow(deprecated)]
|
||||
match authority.zone_type() {
|
||||
ZoneType::Slave | ZoneType::Master => {
|
||||
warn!("Consider replacing the usage of master/slave with primary/secondary, see Juneteenth.");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
match authority.zone_type() {
|
||||
match authority.zone_type().await {
|
||||
ZoneType::Secondary | ZoneType::Slave => {
|
||||
error!("secondary forwarding for update not yet implemented");
|
||||
ResponseCode::NotImp
|
||||
}
|
||||
ZoneType::Primary | ZoneType::Master => {
|
||||
let update_result = authority.update(update);
|
||||
let update_result = authority.update(update).await;
|
||||
match update_result {
|
||||
// successful update
|
||||
Ok(..) => ResponseCode::NoError,
|
||||
@@ -311,6 +302,7 @@ impl Catalog {
|
||||
response.build_no_records(response_header),
|
||||
response_handle,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Checks whether the `Catalog` contains DNS records for `name`
|
||||
@@ -332,12 +324,12 @@ impl Catalog {
|
||||
///
|
||||
/// * `request` - the query message.
|
||||
/// * `response_handle` - sink for the response message to be sent
|
||||
pub fn lookup<R: ResponseHandler>(
|
||||
pub async fn lookup<R: ResponseHandler>(
|
||||
&self,
|
||||
request: MessageRequest,
|
||||
response_edns: Option<Edns>,
|
||||
response_handle: R,
|
||||
) -> impl Future<Output = ()> + 'static {
|
||||
) {
|
||||
// find matching authorities for the request
|
||||
let queries_and_authorities = request
|
||||
.queries()
|
||||
@@ -360,6 +352,7 @@ impl Catalog {
|
||||
response.error_msg(request.header(), ResponseCode::Refused),
|
||||
response_handle.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| error!("failed to send response: {}", e))
|
||||
.ok();
|
||||
}
|
||||
@@ -370,6 +363,7 @@ impl Catalog {
|
||||
response_edns,
|
||||
response_handle,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Recursively searches the catalog for a matching authority
|
||||
@@ -403,7 +397,7 @@ async fn lookup<R: ResponseHandler + Unpin>(
|
||||
info!(
|
||||
"request: {} found authority: {}",
|
||||
request.id(),
|
||||
authority.origin()
|
||||
authority.origin().await
|
||||
);
|
||||
|
||||
let (response_header, sections) = build_response(
|
||||
@@ -423,7 +417,7 @@ async fn lookup<R: ResponseHandler + Unpin>(
|
||||
sections.additionals.iter(),
|
||||
);
|
||||
|
||||
let result = send_response(response_edns.clone(), response, response_handle.clone());
|
||||
let result = send_response(response_edns.clone(), response, response_handle.clone()).await;
|
||||
if let Err(e) = result {
|
||||
error!("error sending response: {}", e);
|
||||
}
|
||||
@@ -472,13 +466,13 @@ async fn build_response(
|
||||
}
|
||||
|
||||
let mut response_header = Header::response_from_request(request_header);
|
||||
response_header.set_authoritative(authority.zone_type().is_authoritative());
|
||||
response_header.set_authoritative(authority.zone_type().await.is_authoritative());
|
||||
|
||||
debug!("performing {} on {}", query, authority.origin());
|
||||
debug!("performing {} on {}", query, authority.origin().await);
|
||||
let future = authority.search(query, lookup_options);
|
||||
|
||||
#[allow(deprecated)]
|
||||
let sections = match authority.zone_type() {
|
||||
let sections = match authority.zone_type().await {
|
||||
ZoneType::Primary | ZoneType::Secondary | ZoneType::Master | ZoneType::Slave => {
|
||||
send_authoritative_response(
|
||||
future,
|
||||
@@ -499,7 +493,7 @@ async fn build_response(
|
||||
}
|
||||
|
||||
async fn send_authoritative_response(
|
||||
future: BoxedLookupFuture,
|
||||
future: impl Future<Output = Result<Box<dyn LookupObject>, LookupError>>,
|
||||
authority: &dyn AuthorityObject,
|
||||
response_header: &mut Header,
|
||||
lookup_options: LookupOptions,
|
||||
@@ -603,7 +597,7 @@ async fn send_authoritative_response(
|
||||
}
|
||||
|
||||
async fn send_forwarded_response(
|
||||
future: BoxedLookupFuture,
|
||||
future: impl Future<Output = Result<Box<dyn LookupObject>, LookupError>>,
|
||||
request_header: &Header,
|
||||
response_header: &mut Header,
|
||||
) -> LookupSections {
|
||||
|
@@ -26,7 +26,7 @@ pub use self::auth_lookup::{
|
||||
AnyRecords, AuthLookup, AuthLookupIter, LookupRecords, LookupRecordsIter,
|
||||
};
|
||||
pub use self::authority::{Authority, LookupOptions};
|
||||
pub use self::authority_object::{AuthorityObject, BoxedLookupFuture, EmptyLookup, LookupObject};
|
||||
pub use self::authority_object::{AuthorityObject, EmptyLookup, LookupObject};
|
||||
pub use self::catalog::Catalog;
|
||||
pub use self::error::{LookupError, LookupResult};
|
||||
pub use self::message_request::{MessageRequest, Queries, UpdateRequest};
|
||||
|
@@ -5,21 +5,19 @@
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{io, net::SocketAddr, sync::Arc};
|
||||
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use futures_util::lock::Mutex;
|
||||
use h2::server;
|
||||
use log::{debug, warn};
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use crate::authority::{MessageRequest, MessageResponse};
|
||||
use crate::proto::https::https_server;
|
||||
use crate::proto::serialize::binary::BinDecodable;
|
||||
use crate::server::request_handler::RequestHandler;
|
||||
use crate::server::response_handler::ResponseHandler;
|
||||
use crate::server::server_future;
|
||||
use crate::{
|
||||
authority::{MessageRequest, MessageResponse},
|
||||
proto::{https::https_server, serialize::binary::BinDecodable},
|
||||
server::{request_handler::RequestHandler, response_handler::ResponseHandler, server_future},
|
||||
};
|
||||
|
||||
pub(crate) async fn h2_handler<T, I>(
|
||||
handler: Arc<Mutex<T>>,
|
||||
@@ -90,8 +88,9 @@ async fn handle_request<T>(
|
||||
#[derive(Clone)]
|
||||
struct HttpsResponseHandle(Arc<Mutex<::h2::server::SendResponse<Bytes>>>);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ResponseHandler for HttpsResponseHandle {
|
||||
fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()> {
|
||||
async fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()> {
|
||||
use crate::proto::https::response;
|
||||
use crate::proto::https::HttpsError;
|
||||
use crate::proto::serialize::binary::BinEncoder;
|
||||
@@ -109,7 +108,7 @@ impl ResponseHandler for HttpsResponseHandle {
|
||||
let mut stream = self
|
||||
.0
|
||||
.lock()
|
||||
.expect("https poisoned")
|
||||
.await
|
||||
.send_response(response, false)
|
||||
.map_err(HttpsError::from)?;
|
||||
stream.send_data(bytes, true).map_err(HttpsError::from)?;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
@@ -7,11 +7,9 @@
|
||||
|
||||
//! Request Handler for incoming requests
|
||||
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use crate::authority::MessageRequest;
|
||||
use crate::server::ResponseHandler;
|
||||
use crate::{authority::MessageRequest, server::ResponseHandler};
|
||||
|
||||
/// An incoming request to the DNS catalog
|
||||
pub struct Request {
|
||||
@@ -22,19 +20,13 @@ pub struct Request {
|
||||
}
|
||||
|
||||
/// Trait for handling incoming requests, and providing a message response.
|
||||
pub trait RequestHandler: Send + Unpin + 'static {
|
||||
/// A future for execution of the request
|
||||
type ResponseFuture: Future<Output = ()> + Send + Unpin + 'static;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait RequestHandler: Send + Sync + Unpin + 'static {
|
||||
/// Determines what needs to happen given the type of request, i.e. Query or Update.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `request` - the requested action to perform.
|
||||
/// * `response_handle` - handle to which a return message should be sent
|
||||
fn handle_request<R: ResponseHandler>(
|
||||
&self,
|
||||
request: Request,
|
||||
response_handle: R,
|
||||
) -> Self::ResponseFuture;
|
||||
async fn handle_request<R: ResponseHandler>(&self, request: Request, response_handle: R);
|
||||
}
|
||||
|
@@ -16,14 +16,15 @@ use crate::proto::xfer::SerialMessage;
|
||||
use crate::proto::{BufDnsStreamHandle, DnsStreamHandle};
|
||||
|
||||
/// A handler for send a response to a client
|
||||
pub trait ResponseHandler: Clone + Send + Unpin + 'static {
|
||||
#[async_trait::async_trait]
|
||||
pub trait ResponseHandler: Clone + Send + Sync + Unpin + 'static {
|
||||
// TODO: add associated error type
|
||||
//type Error;
|
||||
|
||||
/// Serializes and sends a message to to the wrapped handle
|
||||
///
|
||||
/// self is consumed as only one message should ever be sent in response to a Request
|
||||
fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()>;
|
||||
async fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()>;
|
||||
}
|
||||
|
||||
/// A handler for wrapping a BufStreamHandle, which will properly serialize the message and add the
|
||||
@@ -41,11 +42,12 @@ impl ResponseHandle {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ResponseHandler for ResponseHandle {
|
||||
/// Serializes and sends a message to to the wrapped handle
|
||||
///
|
||||
/// self is consumed as only one message should ever be sent in response to a Request
|
||||
fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()> {
|
||||
async fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()> {
|
||||
info!(
|
||||
"response: {} response_code: {}",
|
||||
response.header().id(),
|
||||
|
@@ -1,23 +1,16 @@
|
||||
// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
use std::{io, net::SocketAddr, sync::Arc, time::Duration};
|
||||
|
||||
use futures_util::{future, FutureExt, StreamExt};
|
||||
use futures_util::{future, lock::Mutex, StreamExt};
|
||||
use log::{debug, info, warn};
|
||||
#[cfg(feature = "dns-over-rustls")]
|
||||
use rustls::{Certificate, PrivateKey};
|
||||
use tokio::net;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::{net, task::JoinHandle};
|
||||
|
||||
use crate::authority::MessageRequest;
|
||||
use crate::proto::error::ProtoError;
|
||||
@@ -78,7 +71,7 @@ impl<T: RequestHandler> ServerFuture<T> {
|
||||
let stream_handle = stream_handle.with_remote_addr(src_addr);
|
||||
|
||||
tokio::spawn(async move {
|
||||
self::handle_raw_request(message, handler, stream_handle).await;
|
||||
self::handle_raw_request(message, handler, stream_handle).await
|
||||
});
|
||||
}
|
||||
|
||||
@@ -557,11 +550,11 @@ impl<T: RequestHandler> ServerFuture<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_raw_request<T: RequestHandler>(
|
||||
pub(crate) async fn handle_raw_request<T: RequestHandler>(
|
||||
message: SerialMessage,
|
||||
request_handler: Arc<Mutex<T>>,
|
||||
response_handler: BufDnsStreamHandle,
|
||||
) -> HandleRawRequest<T::ResponseFuture> {
|
||||
) {
|
||||
let src_addr = message.addr();
|
||||
let response_handler = ResponseHandle::new(message.addr(), response_handler);
|
||||
|
||||
@@ -572,20 +565,19 @@ pub(crate) fn handle_raw_request<T: RequestHandler>(
|
||||
let mut decoder = BinDecoder::new(message.bytes());
|
||||
match MessageRequest::read(&mut decoder) {
|
||||
Ok(message) => {
|
||||
let handle_request =
|
||||
self::handle_request(message, src_addr, request_handler, response_handler);
|
||||
HandleRawRequest::HandleRequest(handle_request)
|
||||
self::handle_request(message, src_addr, request_handler, response_handler).await
|
||||
}
|
||||
Err(e) => HandleRawRequest::Result(e.into()),
|
||||
// FIXME: return the error and properly log it in handle_request?
|
||||
Err(e) => warn!("failed to handle message: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_request<R: ResponseHandler, T: RequestHandler>(
|
||||
pub(crate) async fn handle_request<R: ResponseHandler, T: RequestHandler>(
|
||||
message: MessageRequest,
|
||||
src_addr: SocketAddr,
|
||||
request_handler: Arc<Mutex<T>>,
|
||||
response_handler: R,
|
||||
) -> T::ResponseFuture {
|
||||
) {
|
||||
let request = Request {
|
||||
message,
|
||||
src: src_addr,
|
||||
@@ -607,26 +599,7 @@ pub(crate) fn handle_request<R: ResponseHandler, T: RequestHandler>(
|
||||
|
||||
request_handler
|
||||
.lock()
|
||||
.expect("poisoned lock")
|
||||
.await
|
||||
.handle_request(request, response_handler)
|
||||
}
|
||||
|
||||
#[must_use = "futures do nothing unless polled"]
|
||||
pub(crate) enum HandleRawRequest<F: Future<Output = ()>> {
|
||||
HandleRequest(F),
|
||||
Result(io::Error),
|
||||
}
|
||||
|
||||
impl<F: Future<Output = ()> + Unpin> Future for HandleRawRequest<F> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match *self {
|
||||
HandleRawRequest::HandleRequest(ref mut f) => f.poll_unpin(cx),
|
||||
HandleRawRequest::Result(ref res) => {
|
||||
warn!("failed to handle message: {}", res);
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
@@ -7,31 +7,33 @@
|
||||
|
||||
//! All authority related types
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::future::Future;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fs::File,
|
||||
io::{BufRead, BufReader},
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use log::{debug, info};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::authority::DnssecAuthority;
|
||||
use crate::authority::{
|
||||
Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType,
|
||||
use crate::{
|
||||
authority::DnssecAuthority,
|
||||
client::{
|
||||
proto::rr::dnssec::rdata::key::KEY,
|
||||
rr::dnssec::{DnsSecResult, SigSigner},
|
||||
},
|
||||
};
|
||||
use crate::client::op::LowerQuery;
|
||||
use crate::client::rr::{LowerName, Name, RecordSet, RecordType, RrKey};
|
||||
use crate::client::serialize::txt::{Lexer, Parser, Token};
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::client::{
|
||||
proto::rr::dnssec::rdata::key::KEY,
|
||||
rr::dnssec::{DnsSecResult, SigSigner},
|
||||
use crate::{
|
||||
authority::{Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType},
|
||||
client::{
|
||||
op::LowerQuery,
|
||||
rr::{LowerName, Name, RecordSet, RecordType, RrKey},
|
||||
serialize::txt::{Lexer, Parser, Token},
|
||||
},
|
||||
store::{file::FileConfig, in_memory::InMemoryAuthority},
|
||||
};
|
||||
use crate::store::file::FileConfig;
|
||||
use crate::store::in_memory::InMemoryAuthority;
|
||||
|
||||
/// FileAuthority is responsible for storing the resource records for a particular zone.
|
||||
///
|
||||
@@ -232,9 +234,9 @@ impl DerefMut for FileAuthority {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Authority for FileAuthority {
|
||||
type Lookup = <InMemoryAuthority as Authority>::Lookup;
|
||||
type LookupFuture = <InMemoryAuthority as Authority>::LookupFuture;
|
||||
|
||||
/// What type is this zone
|
||||
fn zone_type(&self) -> ZoneType {
|
||||
@@ -247,7 +249,7 @@ impl Authority for FileAuthority {
|
||||
}
|
||||
|
||||
/// Perform a dynamic update of a zone
|
||||
fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
async fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
use crate::proto::op::ResponseCode;
|
||||
Err(ResponseCode::NotImp)
|
||||
}
|
||||
@@ -271,13 +273,13 @@ impl Authority for FileAuthority {
|
||||
/// # Return value
|
||||
///
|
||||
/// None if there are no matching records, otherwise a `Vec` containing the found records.
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
rtype: RecordType,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
Box::pin(self.0.lookup(name, rtype, lookup_options))
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.0.lookup(name, rtype, lookup_options).await
|
||||
}
|
||||
|
||||
/// Using the specified query, perform a lookup against this zone.
|
||||
@@ -291,20 +293,17 @@ impl Authority for FileAuthority {
|
||||
///
|
||||
/// Returns a vectory containing the results of the query, it will be empty if not found. If
|
||||
/// `is_secure` is true, in the case of no records found then NSEC records will be returned.
|
||||
fn search(
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
Box::pin(self.0.search(query, lookup_options))
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.0.search(query, lookup_options).await
|
||||
}
|
||||
|
||||
/// Get the NS, NameServer, record for the zone
|
||||
fn ns(
|
||||
&self,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.0.ns(lookup_options)
|
||||
async fn ns(&self, lookup_options: LookupOptions) -> Result<Self::Lookup, LookupError> {
|
||||
self.0.ns(lookup_options).await
|
||||
}
|
||||
|
||||
/// Return the NSEC records based on the given name
|
||||
@@ -314,28 +313,25 @@ impl Authority for FileAuthority {
|
||||
/// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
|
||||
/// this
|
||||
/// * `is_secure` - if true then it will return RRSIG records as well
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.0.get_nsec_records(name, lookup_options)
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.0.get_nsec_records(name, lookup_options).await
|
||||
}
|
||||
|
||||
/// Returns the SOA of the authority.
|
||||
///
|
||||
/// *Note*: This will only return the SOA, if this is fulfilling a request, a standard lookup
|
||||
/// should be used, see `soa_secure()`, which will optionally return RRSIGs.
|
||||
fn soa(&self) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.0.soa()
|
||||
async fn soa(&self) -> Result<Self::Lookup, LookupError> {
|
||||
self.0.soa().await
|
||||
}
|
||||
|
||||
/// Returns the SOA record for the zone
|
||||
fn soa_secure(
|
||||
&self,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.0.soa_secure(lookup_options)
|
||||
async fn soa_secure(&self, lookup_options: LookupOptions) -> Result<Self::Lookup, LookupError> {
|
||||
self.0.soa_secure(lookup_options).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,30 +1,27 @@
|
||||
// Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
// http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
// copied, modified, or distributed except according to those terms.
|
||||
|
||||
use std::future::Future;
|
||||
use std::io;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use futures_util::{future, FutureExt};
|
||||
use log::info;
|
||||
|
||||
use crate::client::op::LowerQuery;
|
||||
use crate::client::op::ResponseCode;
|
||||
use crate::client::rr::{LowerName, Name, Record, RecordType};
|
||||
use crate::resolver::config::ResolverConfig;
|
||||
use crate::resolver::error::ResolveError;
|
||||
use crate::resolver::lookup::Lookup as ResolverLookup;
|
||||
use crate::resolver::{TokioAsyncResolver, TokioHandle};
|
||||
|
||||
use crate::authority::{
|
||||
Authority, LookupError, LookupObject, LookupOptions, MessageRequest, UpdateResult, ZoneType,
|
||||
use crate::{
|
||||
authority::{
|
||||
Authority, LookupError, LookupObject, LookupOptions, MessageRequest, UpdateResult, ZoneType,
|
||||
},
|
||||
client::{
|
||||
op::{LowerQuery, ResponseCode},
|
||||
rr::{LowerName, Name, Record, RecordType},
|
||||
},
|
||||
resolver::{
|
||||
config::ResolverConfig, lookup::Lookup as ResolverLookup, TokioAsyncResolver, TokioHandle,
|
||||
},
|
||||
store::forwarder::ForwardConfig,
|
||||
};
|
||||
use crate::store::forwarder::ForwardConfig;
|
||||
|
||||
/// An authority that will forward resolutions to upstream resolvers.
|
||||
///
|
||||
@@ -73,9 +70,9 @@ impl ForwardAuthority {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Authority for ForwardAuthority {
|
||||
type Lookup = ForwardLookup;
|
||||
type LookupFuture = Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>>;
|
||||
|
||||
/// Always Forward
|
||||
fn zone_type(&self) -> ZoneType {
|
||||
@@ -87,7 +84,7 @@ impl Authority for ForwardAuthority {
|
||||
false
|
||||
}
|
||||
|
||||
fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
async fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
Err(ResponseCode::NotImp)
|
||||
}
|
||||
|
||||
@@ -101,41 +98,40 @@ impl Authority for ForwardAuthority {
|
||||
}
|
||||
|
||||
/// Forwards a lookup given the resolver configuration for this Forwarded zone
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
rtype: RecordType,
|
||||
_lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
// TODO: make this an error?
|
||||
assert!(self.origin.zone_of(name));
|
||||
|
||||
info!("forwarding lookup: {} {}", name, rtype);
|
||||
let name: LowerName = name.clone();
|
||||
Box::pin(ForwardLookupFuture(self.resolver.lookup(
|
||||
name,
|
||||
rtype,
|
||||
Default::default(),
|
||||
)))
|
||||
let resolve = self.resolver.lookup(name, rtype, Default::default()).await;
|
||||
|
||||
resolve.map(ForwardLookup).map_err(LookupError::from)
|
||||
}
|
||||
|
||||
fn search(
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
Box::pin(self.lookup(query.name(), query.query_type(), lookup_options))
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.lookup(query.name(), query.query_type(), lookup_options)
|
||||
.await
|
||||
}
|
||||
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
_name: &LowerName,
|
||||
_lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
Box::pin(future::err(LookupError::from(io::Error::new(
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
Err(LookupError::from(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Getting NSEC records is unimplemented for the forwarder",
|
||||
))))
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,21 +150,3 @@ impl LookupObject for ForwardLookup {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ForwardLookupFuture<
|
||||
F: Future<Output = Result<ResolverLookup, ResolveError>> + Send + Unpin + 'static,
|
||||
>(F);
|
||||
|
||||
impl<F: Future<Output = Result<ResolverLookup, ResolveError>> + Send + Unpin> Future
|
||||
for ForwardLookupFuture<F>
|
||||
{
|
||||
type Output = Result<ForwardLookup, LookupError>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
match self.0.poll_unpin(cx) {
|
||||
Poll::Ready(Ok(f)) => Poll::Ready(Ok(ForwardLookup(f))),
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
@@ -7,11 +7,7 @@
|
||||
|
||||
//! All authority related types
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::{borrow::Borrow, collections::BTreeMap, sync::Arc};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use futures_util::future::{self, TryFutureExt};
|
||||
@@ -709,9 +705,9 @@ fn maybe_next_name(
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Authority for InMemoryAuthority {
|
||||
type Lookup = AuthLookup;
|
||||
type LookupFuture = future::Ready<Result<Self::Lookup, LookupError>>;
|
||||
|
||||
/// What type is this zone
|
||||
fn zone_type(&self) -> ZoneType {
|
||||
@@ -780,7 +776,7 @@ impl Authority for InMemoryAuthority {
|
||||
///
|
||||
/// true if any of additions, updates or deletes were made to the zone, false otherwise. Err is
|
||||
/// returned in the case of bad data, etc.
|
||||
fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
async fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
Err(ResponseCode::NotImp)
|
||||
}
|
||||
|
||||
@@ -803,12 +799,12 @@ impl Authority for InMemoryAuthority {
|
||||
/// # Return value
|
||||
///
|
||||
/// None if there are no matching records, otherwise a `Vec` containing the found records.
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
query_type: RecordType,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
// Collect the records from each rr_set
|
||||
let (result, additionals): (LookupResult<LookupRecords>, Option<LookupRecords>) =
|
||||
match query_type {
|
||||
@@ -944,30 +940,28 @@ impl Authority for InMemoryAuthority {
|
||||
.keys()
|
||||
.any(|key| key.name() == name || name.zone_of(key.name()))
|
||||
{
|
||||
return Box::pin(future::err(LookupError::NameExists));
|
||||
return Err(LookupError::NameExists);
|
||||
} else {
|
||||
let code = if self.origin().zone_of(name) {
|
||||
ResponseCode::NXDomain
|
||||
} else {
|
||||
ResponseCode::Refused
|
||||
};
|
||||
return Box::pin(future::err(LookupError::from(code)));
|
||||
return Err(LookupError::from(code));
|
||||
}
|
||||
}
|
||||
Err(e) => return Box::pin(future::err(e)),
|
||||
Err(e) => return Err(e),
|
||||
o => o,
|
||||
};
|
||||
|
||||
Box::pin(future::ready(
|
||||
result.map(|answers| AuthLookup::answers(answers, additionals)),
|
||||
))
|
||||
result.map(|answers| AuthLookup::answers(answers, additionals))
|
||||
}
|
||||
|
||||
fn search(
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
debug!("searching InMemoryAuthority for: {}", query);
|
||||
|
||||
let lookup_name = query.name();
|
||||
@@ -978,20 +972,23 @@ impl Authority for InMemoryAuthority {
|
||||
if RecordType::AXFR == record_type {
|
||||
// TODO: support more advanced AXFR options
|
||||
if !self.is_axfr_allowed() {
|
||||
return Box::pin(future::err(LookupError::from(ResponseCode::Refused)));
|
||||
return Err(LookupError::from(ResponseCode::Refused));
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
match self.zone_type() {
|
||||
ZoneType::Primary | ZoneType::Secondary | ZoneType::Master | ZoneType::Slave => (),
|
||||
// TODO: Forward?
|
||||
_ => return Box::pin(future::err(LookupError::from(ResponseCode::NXDomain))),
|
||||
_ => return Err(LookupError::from(ResponseCode::NXDomain)),
|
||||
}
|
||||
}
|
||||
|
||||
// perform the actual lookup
|
||||
match record_type {
|
||||
RecordType::SOA => Box::pin(self.lookup(self.origin(), record_type, lookup_options)),
|
||||
RecordType::SOA => {
|
||||
self.lookup(self.origin(), record_type, lookup_options)
|
||||
.await
|
||||
}
|
||||
RecordType::AXFR => {
|
||||
// TODO: shouldn't these SOA's be secure? at least the first, perhaps not the last?
|
||||
let lookup = future::try_join3(
|
||||
@@ -1009,10 +1006,10 @@ impl Authority for InMemoryAuthority {
|
||||
},
|
||||
});
|
||||
|
||||
Box::pin(lookup)
|
||||
lookup.await
|
||||
}
|
||||
// A standard Lookup path
|
||||
_ => Box::pin(self.lookup(lookup_name, record_type, lookup_options)),
|
||||
_ => self.lookup(lookup_name, record_type, lookup_options).await,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,11 +1021,11 @@ impl Authority for InMemoryAuthority {
|
||||
/// this
|
||||
/// * `is_secure` - if true then it will return RRSIG records as well
|
||||
#[cfg(feature = "dnssec")]
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
fn is_nsec_rrset(rr_set: &RecordSet) -> bool {
|
||||
rr_set.record_type() == RecordType::NSEC
|
||||
}
|
||||
@@ -1041,7 +1038,7 @@ impl Authority for InMemoryAuthority {
|
||||
.map(|rr_set| LookupRecords::new(lookup_options, rr_set.clone()));
|
||||
|
||||
if let Some(no_data) = no_data {
|
||||
return Box::pin(future::ready(Ok(no_data.into())));
|
||||
return Ok(no_data.into());
|
||||
}
|
||||
|
||||
let get_closest_nsec = |name: &LowerName| -> Option<Arc<RecordSet>> {
|
||||
@@ -1099,20 +1096,16 @@ impl Authority for InMemoryAuthority {
|
||||
(None, None) => vec![],
|
||||
};
|
||||
|
||||
Box::pin(future::ready(Ok(LookupRecords::many(
|
||||
lookup_options,
|
||||
proofs,
|
||||
)
|
||||
.into())))
|
||||
Ok(LookupRecords::many(lookup_options, proofs).into())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "dnssec"))]
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
_name: &LowerName,
|
||||
_lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
Box::pin(future::ok(AuthLookup::default()))
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
Ok(AuthLookup::default())
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
|
||||
// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
@@ -7,24 +7,30 @@
|
||||
|
||||
//! All authority related types
|
||||
|
||||
use std::future::Future;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use log::{error, info, warn};
|
||||
|
||||
use crate::authority::{
|
||||
Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType,
|
||||
use crate::{
|
||||
authority::{Authority, LookupError, LookupOptions, MessageRequest, UpdateResult, ZoneType},
|
||||
client::{
|
||||
op::LowerQuery,
|
||||
rr::{LowerName, RrKey},
|
||||
},
|
||||
error::{PersistenceErrorKind, PersistenceResult},
|
||||
proto::{
|
||||
op::ResponseCode,
|
||||
rr::{DNSClass, Name, RData, Record, RecordSet, RecordType},
|
||||
},
|
||||
store::{
|
||||
in_memory::InMemoryAuthority,
|
||||
sqlite::{Journal, SqliteConfig},
|
||||
},
|
||||
};
|
||||
use crate::client::op::LowerQuery;
|
||||
use crate::client::rr::{LowerName, RrKey};
|
||||
use crate::error::{PersistenceErrorKind, PersistenceResult};
|
||||
use crate::proto::op::ResponseCode;
|
||||
use crate::proto::rr::{DNSClass, Name, RData, Record, RecordSet, RecordType};
|
||||
use crate::store::in_memory::InMemoryAuthority;
|
||||
use crate::store::sqlite::{Journal, SqliteConfig};
|
||||
#[cfg(feature = "dnssec")]
|
||||
use crate::{
|
||||
authority::{DnssecAuthority, UpdateRequest},
|
||||
@@ -258,9 +264,7 @@ impl SqliteAuthority {
|
||||
/// NONE rrset empty RRset does not exist
|
||||
/// zone rrset rr RRset exists (value dependent)
|
||||
/// ```
|
||||
pub fn verify_prerequisites(&self, pre_requisites: &[Record]) -> UpdateResult<()> {
|
||||
use futures_executor::block_on;
|
||||
|
||||
pub async fn verify_prerequisites(&self, pre_requisites: &[Record]) -> UpdateResult<()> {
|
||||
// 3.2.5 - Pseudocode for Prerequisite Section Processing
|
||||
//
|
||||
// for rr in prerequisites
|
||||
@@ -313,14 +317,15 @@ impl SqliteAuthority {
|
||||
match require.rr_type() {
|
||||
// ANY ANY empty Name is in use
|
||||
RecordType::ANY => {
|
||||
/*TODO: this works because the future here is always complete*/
|
||||
if block_on(self.lookup(
|
||||
&required_name,
|
||||
RecordType::ANY,
|
||||
LookupOptions::default(),
|
||||
))
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
if self
|
||||
.lookup(
|
||||
&required_name,
|
||||
RecordType::ANY,
|
||||
LookupOptions::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
{
|
||||
return Err(ResponseCode::NXDomain);
|
||||
} else {
|
||||
@@ -329,14 +334,11 @@ impl SqliteAuthority {
|
||||
}
|
||||
// ANY rrset empty RRset exists (value independent)
|
||||
rrset => {
|
||||
/*TODO: this works because the future here is always complete*/
|
||||
if block_on(self.lookup(
|
||||
&required_name,
|
||||
rrset,
|
||||
LookupOptions::default(),
|
||||
))
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
if self
|
||||
.lookup(&required_name, rrset, LookupOptions::default())
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
{
|
||||
return Err(ResponseCode::NXRRSet);
|
||||
} else {
|
||||
@@ -353,14 +355,15 @@ impl SqliteAuthority {
|
||||
match require.rr_type() {
|
||||
// NONE ANY empty Name is not in use
|
||||
RecordType::ANY => {
|
||||
/*TODO: this works because the future here is always complete*/
|
||||
if !block_on(self.lookup(
|
||||
&required_name,
|
||||
RecordType::ANY,
|
||||
LookupOptions::default(),
|
||||
))
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
if !self
|
||||
.lookup(
|
||||
&required_name,
|
||||
RecordType::ANY,
|
||||
LookupOptions::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
{
|
||||
return Err(ResponseCode::YXDomain);
|
||||
} else {
|
||||
@@ -369,14 +372,11 @@ impl SqliteAuthority {
|
||||
}
|
||||
// NONE rrset empty RRset does not exist
|
||||
rrset => {
|
||||
/*TODO: this works because the future here is always complete*/
|
||||
if !block_on(self.lookup(
|
||||
&required_name,
|
||||
rrset,
|
||||
LookupOptions::default(),
|
||||
))
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
if !self
|
||||
.lookup(&required_name, rrset, LookupOptions::default())
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.was_empty()
|
||||
{
|
||||
return Err(ResponseCode::YXRRSet);
|
||||
} else {
|
||||
@@ -391,15 +391,12 @@ impl SqliteAuthority {
|
||||
class if class == self.class() =>
|
||||
// zone rrset rr RRset exists (value dependent)
|
||||
{
|
||||
/*TODO: this works because the future here is always complete*/
|
||||
if !block_on(self.lookup(
|
||||
&required_name,
|
||||
require.rr_type(),
|
||||
LookupOptions::default(),
|
||||
))
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.any(|rr| rr == require)
|
||||
if !self
|
||||
.lookup(&required_name, require.rr_type(), LookupOptions::default())
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.any(|rr| rr == require)
|
||||
{
|
||||
return Err(ResponseCode::NXRRSet);
|
||||
} else {
|
||||
@@ -440,8 +437,7 @@ impl SqliteAuthority {
|
||||
#[cfg(feature = "dnssec")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
|
||||
#[allow(clippy::blocks_in_if_conditions)]
|
||||
pub fn authorize(&self, update_message: &MessageRequest) -> UpdateResult<()> {
|
||||
use futures_executor::block_on;
|
||||
pub async fn authorize(&self, update_message: &MessageRequest) -> UpdateResult<()> {
|
||||
use log::debug;
|
||||
|
||||
use crate::client::rr::rdata::DNSSECRData;
|
||||
@@ -468,51 +464,56 @@ impl SqliteAuthority {
|
||||
// verify sig0, currently the only authorization that is accepted.
|
||||
let sig0s: &[Record] = update_message.sig0();
|
||||
debug!("authorizing with: {:?}", sig0s);
|
||||
if !sig0s.is_empty()
|
||||
&& sig0s
|
||||
.iter()
|
||||
.filter_map(|sig0| {
|
||||
if let RData::DNSSEC(DNSSECRData::SIG(ref sig)) = *sig0.rdata() {
|
||||
Some(sig)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.any(|sig| {
|
||||
let name = LowerName::from(sig.signer_name());
|
||||
// TODO: updates should be async as well.
|
||||
let keys =
|
||||
block_on(self.lookup(&name, RecordType::KEY, LookupOptions::default()));
|
||||
if !sig0s.is_empty() {
|
||||
let mut found_key = false;
|
||||
for sig in sig0s.iter().filter_map(|sig0| {
|
||||
if let RData::DNSSEC(DNSSECRData::SIG(ref sig)) = *sig0.rdata() {
|
||||
Some(sig)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
let name = LowerName::from(sig.signer_name());
|
||||
let keys = self
|
||||
.lookup(&name, RecordType::KEY, LookupOptions::default())
|
||||
.await;
|
||||
|
||||
let keys = match keys {
|
||||
Ok(keys) => keys,
|
||||
Err(_) => return false,
|
||||
};
|
||||
let keys = match keys {
|
||||
Ok(keys) => keys,
|
||||
Err(_) => continue, // error trying to lookup a key by that name, try the next one.
|
||||
};
|
||||
|
||||
debug!("found keys {:?}", keys);
|
||||
// TODO: check key usage flags and restrictions
|
||||
keys.iter()
|
||||
.filter_map(|rr_set| {
|
||||
if let RData::DNSSEC(DNSSECRData::KEY(ref key)) = *rr_set.rdata() {
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.any(|key| {
|
||||
key.verify_message(update_message, sig.sig(), sig)
|
||||
.map(|_| {
|
||||
info!("verified sig: {:?} with key: {:?}", sig, key);
|
||||
true
|
||||
})
|
||||
.unwrap_or_else(|_| {
|
||||
debug!("did not verify sig: {:?} with key: {:?}", sig, key);
|
||||
false
|
||||
})
|
||||
})
|
||||
})
|
||||
{
|
||||
return Ok(());
|
||||
debug!("found keys {:?}", keys);
|
||||
// TODO: check key usage flags and restrictions
|
||||
found_key = keys
|
||||
.iter()
|
||||
.filter_map(|rr_set| {
|
||||
if let RData::DNSSEC(DNSSECRData::KEY(ref key)) = *rr_set.rdata() {
|
||||
Some(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.any(|key| {
|
||||
key.verify_message(update_message, sig.sig(), sig)
|
||||
.map(|_| {
|
||||
info!("verified sig: {:?} with key: {:?}", sig, key);
|
||||
true
|
||||
})
|
||||
.unwrap_or_else(|_| {
|
||||
debug!("did not verify sig: {:?} with key: {:?}", sig, key);
|
||||
false
|
||||
})
|
||||
});
|
||||
|
||||
if found_key {
|
||||
break; // stop searching for matching keys, we found one
|
||||
}
|
||||
}
|
||||
|
||||
if found_key {
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"no sig0 matched registered records: id {}",
|
||||
@@ -825,9 +826,9 @@ impl DerefMut for SqliteAuthority {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Authority for SqliteAuthority {
|
||||
type Lookup = <InMemoryAuthority as Authority>::Lookup;
|
||||
type LookupFuture = <InMemoryAuthority as Authority>::LookupFuture;
|
||||
|
||||
/// What type is this zone
|
||||
fn zone_type(&self) -> ZoneType {
|
||||
@@ -897,10 +898,10 @@ impl Authority for SqliteAuthority {
|
||||
/// true if any of additions, updates or deletes were made to the zone, false otherwise. Err is
|
||||
/// returned in the case of bad data, etc.
|
||||
#[cfg(feature = "dnssec")]
|
||||
fn update(&mut self, update: &MessageRequest) -> UpdateResult<bool> {
|
||||
async fn update(&mut self, update: &MessageRequest) -> UpdateResult<bool> {
|
||||
// the spec says to authorize after prereqs, seems better to auth first.
|
||||
self.authorize(update)?;
|
||||
self.verify_prerequisites(update.prerequisites())?;
|
||||
self.authorize(update).await?;
|
||||
self.verify_prerequisites(update.prerequisites()).await?;
|
||||
self.pre_scan(update.updates())?;
|
||||
|
||||
self.update_records(update.updates(), true)
|
||||
@@ -908,7 +909,7 @@ impl Authority for SqliteAuthority {
|
||||
|
||||
/// Always fail when DNSSEC is disabled.
|
||||
#[cfg(not(feature = "dnssec"))]
|
||||
fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
async fn update(&mut self, _update: &MessageRequest) -> UpdateResult<bool> {
|
||||
Err(ResponseCode::NotImp)
|
||||
}
|
||||
|
||||
@@ -931,21 +932,21 @@ impl Authority for SqliteAuthority {
|
||||
/// # Return value
|
||||
///
|
||||
/// None if there are no matching records, otherwise a `Vec` containing the found records.
|
||||
fn lookup(
|
||||
async fn lookup(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
rtype: RecordType,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.in_memory.lookup(name, rtype, lookup_options)
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.in_memory.lookup(name, rtype, lookup_options).await
|
||||
}
|
||||
|
||||
fn search(
|
||||
async fn search(
|
||||
&self,
|
||||
query: &LowerQuery,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.in_memory.search(query, lookup_options)
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.in_memory.search(query, lookup_options).await
|
||||
}
|
||||
|
||||
/// Return the NSEC records based on the given name
|
||||
@@ -955,12 +956,12 @@ impl Authority for SqliteAuthority {
|
||||
/// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
|
||||
/// this
|
||||
/// * `is_secure` - if true then it will return RRSIG records as well
|
||||
fn get_nsec_records(
|
||||
async fn get_nsec_records(
|
||||
&self,
|
||||
name: &LowerName,
|
||||
lookup_options: LookupOptions,
|
||||
) -> Pin<Box<dyn Future<Output = Result<Self::Lookup, LookupError>> + Send>> {
|
||||
self.in_memory.get_nsec_records(name, lookup_options)
|
||||
) -> Result<Self::Lookup, LookupError> {
|
||||
self.in_memory.get_nsec_records(name, lookup_options).await
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -391,7 +391,7 @@ pub fn test_update_errors<A: Authority<Lookup = AuthLookup>>(mut authority: A) {
|
||||
let update = MessageRequest::from_bytes(&bytes).unwrap();
|
||||
|
||||
// this is expected to fail, i.e. updates are not allowed
|
||||
assert!(authority.update(&update).is_err());
|
||||
assert!(block_on(authority.update(&update)).is_err());
|
||||
}
|
||||
|
||||
pub fn test_dots_in_name<A: Authority<Lookup = AuthLookup>>(authority: A) {
|
||||
|
@@ -1,16 +1,19 @@
|
||||
#![cfg(feature = "dnssec")]
|
||||
|
||||
use std::future::Future;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::str::FromStr;
|
||||
use std::{
|
||||
future::Future,
|
||||
net::{Ipv4Addr, Ipv6Addr},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use futures_executor::block_on;
|
||||
|
||||
use trust_dns_client::op::update_message;
|
||||
use trust_dns_client::op::{Message, Query, ResponseCode};
|
||||
use trust_dns_client::proto::rr::{DNSClass, Name, RData, Record, RecordSet, RecordType};
|
||||
use trust_dns_client::rr::dnssec::{Algorithm, SigSigner, SupportedAlgorithms, Verifier};
|
||||
use trust_dns_client::serialize::binary::{BinDecodable, BinEncodable, BinSerializable};
|
||||
use trust_dns_client::{
|
||||
op::{update_message, Message, Query, ResponseCode},
|
||||
proto::rr::{DNSClass, Name, RData, Record, RecordSet, RecordType},
|
||||
rr::dnssec::{Algorithm, SigSigner, SupportedAlgorithms, Verifier},
|
||||
serialize::binary::{BinDecodable, BinEncodable, BinSerializable},
|
||||
};
|
||||
use trust_dns_server::authority::{
|
||||
AuthLookup, Authority, DnssecAuthority, LookupError, LookupOptions, MessageRequest,
|
||||
UpdateResult,
|
||||
@@ -25,7 +28,7 @@ fn update_authority<A: Authority<Lookup = AuthLookup>>(
|
||||
let message = message.to_bytes().unwrap();
|
||||
let request = MessageRequest::from_bytes(&message).unwrap();
|
||||
|
||||
authority.update(&request)
|
||||
block_on(authority.update(&request))
|
||||
}
|
||||
|
||||
pub fn test_create<A: Authority<Lookup = AuthLookup>>(mut authority: A, keys: &[SigSigner]) {
|
||||
|
@@ -69,6 +69,7 @@ dns-over-tls = []
|
||||
sqlite = ["trust-dns-server/sqlite"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.42"
|
||||
chrono = "0.4"
|
||||
env_logger = "0.9"
|
||||
lazy_static = "1.0"
|
||||
|
@@ -96,8 +96,9 @@ impl TestResponseHandler {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ResponseHandler for TestResponseHandler {
|
||||
fn send_response(&mut self, response: MessageResponse) -> io::Result<()> {
|
||||
async fn send_response(&mut self, response: MessageResponse<'_, '_>) -> io::Result<()> {
|
||||
let buf = &mut self.buf.lock().unwrap();
|
||||
buf.clear();
|
||||
let mut encoder = BinEncoder::new(buf);
|
||||
|
@@ -1,9 +1,10 @@
|
||||
use std::net::*;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::executor::block_on;
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use trust_dns_client::op::*;
|
||||
use trust_dns_client::rr::rdata::*;
|
||||
use trust_dns_client::rr::*;
|
||||
@@ -119,8 +120,8 @@ fn test_catalog_lookup() {
|
||||
let test_origin = test.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(test_origin.clone(), Box::new(Arc::new(RwLock::new(test))));
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(Mutex::new(example))));
|
||||
catalog.upsert(test_origin.clone(), Box::new(Arc::new(Mutex::new(test))));
|
||||
|
||||
let mut question: Message = Message::new();
|
||||
|
||||
@@ -190,8 +191,8 @@ fn test_catalog_lookup_soa() {
|
||||
let test_origin = test.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(test_origin, Box::new(Arc::new(RwLock::new(test))));
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(Mutex::new(example))));
|
||||
catalog.upsert(test_origin, Box::new(Arc::new(Mutex::new(test))));
|
||||
|
||||
let mut question: Message = Message::new();
|
||||
|
||||
@@ -254,7 +255,7 @@ fn test_catalog_nx_soa() {
|
||||
let origin = example.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin, Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(origin, Box::new(Arc::new(Mutex::new(example))));
|
||||
|
||||
let mut question: Message = Message::new();
|
||||
|
||||
@@ -299,7 +300,7 @@ fn test_non_authoritive_nx_refused() {
|
||||
let origin = example.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin, Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(origin, Box::new(Arc::new(Mutex::new(example))));
|
||||
|
||||
let mut question: Message = Message::new();
|
||||
|
||||
@@ -350,7 +351,7 @@ fn test_axfr() {
|
||||
.clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(RwLock::new(test))));
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(Mutex::new(test))));
|
||||
|
||||
let mut query: Query = Query::new();
|
||||
query.set_name(origin.clone().into());
|
||||
@@ -467,7 +468,7 @@ fn test_axfr_refused() {
|
||||
let origin = test.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(RwLock::new(test))));
|
||||
catalog.upsert(origin.clone(), Box::new(Arc::new(Mutex::new(test))));
|
||||
|
||||
let mut query: Query = Query::new();
|
||||
query.set_name(origin.into());
|
||||
@@ -503,7 +504,7 @@ fn test_cname_additionals() {
|
||||
let origin = example.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin, Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(origin, Box::new(Arc::new(Mutex::new(example))));
|
||||
|
||||
let mut question: Message = Message::new();
|
||||
|
||||
@@ -547,7 +548,7 @@ fn test_multiple_cname_additionals() {
|
||||
let origin = example.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin, Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(origin, Box::new(Arc::new(Mutex::new(example))));
|
||||
|
||||
let mut question: Message = Message::new();
|
||||
|
||||
|
@@ -1,41 +1,43 @@
|
||||
use std::net::*;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::{
|
||||
net::*,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex as StdMutex},
|
||||
};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
use chrono::Duration;
|
||||
use futures::{Future, FutureExt, TryFutureExt};
|
||||
use tokio::net::TcpStream as TokioTcpStream;
|
||||
use tokio::net::UdpSocket as TokioUdpSocket;
|
||||
use tokio::runtime::Runtime;
|
||||
use futures::{lock::Mutex, Future, FutureExt, TryFutureExt};
|
||||
use tokio::{
|
||||
net::{TcpStream as TokioTcpStream, UdpSocket as TokioUdpSocket},
|
||||
runtime::Runtime,
|
||||
};
|
||||
|
||||
#[cfg(all(feature = "dnssec", feature = "sqlite"))]
|
||||
use trust_dns_client::client::Signer;
|
||||
use trust_dns_client::op::{Message, MessageType, OpCode, Query, ResponseCode};
|
||||
#[cfg(feature = "dnssec")]
|
||||
use trust_dns_client::rr::dnssec::SigSigner;
|
||||
#[cfg(feature = "dnssec")]
|
||||
use trust_dns_client::rr::Record;
|
||||
use trust_dns_client::rr::{DNSClass, Name, RData, RecordSet, RecordType};
|
||||
use trust_dns_client::tcp::TcpClientStream;
|
||||
use trust_dns_client::udp::UdpClientStream;
|
||||
use trust_dns_client::rr::{dnssec::SigSigner, Record};
|
||||
use trust_dns_client::{
|
||||
client::{AsyncClient, ClientHandle},
|
||||
rr::rdata::opt::EdnsOption,
|
||||
error::ClientErrorKind,
|
||||
op::{Edns, Message, MessageType, OpCode, Query, ResponseCode},
|
||||
rr::{
|
||||
rdata::opt::{EdnsCode, EdnsOption},
|
||||
DNSClass, Name, RData, RecordSet, RecordType,
|
||||
},
|
||||
tcp::TcpClientStream,
|
||||
udp::UdpClientStream,
|
||||
};
|
||||
use trust_dns_client::{error::ClientErrorKind, op::Edns, rr::rdata::opt::EdnsCode};
|
||||
use trust_dns_proto::iocompat::AsyncIoTokioAsStd;
|
||||
use trust_dns_proto::xfer::FirstAnswer;
|
||||
#[cfg(feature = "dnssec")]
|
||||
use trust_dns_proto::xfer::{DnsExchangeBackground, DnsMultiplexer};
|
||||
use trust_dns_proto::DnsHandle;
|
||||
#[cfg(all(feature = "dnssec", feature = "sqlite"))]
|
||||
use trust_dns_proto::TokioTime;
|
||||
use trust_dns_proto::{iocompat::AsyncIoTokioAsStd, xfer::FirstAnswer, DnsHandle};
|
||||
|
||||
use trust_dns_server::authority::{Authority, Catalog};
|
||||
|
||||
use trust_dns_integration::authority::create_example;
|
||||
use trust_dns_integration::{NeverReturnsClientStream, TestClientStream};
|
||||
use trust_dns_integration::{
|
||||
authority::create_example, NeverReturnsClientStream, TestClientStream,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_query_nonet() {
|
||||
@@ -45,11 +47,11 @@ fn test_query_nonet() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let client = AsyncClient::new(stream, sender, None);
|
||||
let (mut client, bg) = io_loop.block_on(client).expect("client failed to connect");
|
||||
trust_dns_proto::spawn_bg(&io_loop, bg);
|
||||
@@ -251,11 +253,11 @@ fn test_notify() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let client = AsyncClient::new(stream, sender, None);
|
||||
let (mut client, bg) = io_loop.block_on(client).expect("client failed to connect");
|
||||
trust_dns_proto::spawn_bg(&io_loop, bg);
|
||||
@@ -316,11 +318,11 @@ async fn create_sig0_ready_client() -> (
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let signer = Arc::new(signer.into());
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let client = AsyncClient::new(stream, sender, Some(signer))
|
||||
.await
|
||||
.expect("failed to get new AsyncClient");
|
||||
|
@@ -2,12 +2,13 @@ use std::net::*;
|
||||
use std::pin::Pin;
|
||||
#[cfg(feature = "dnssec")]
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::{Arc, Mutex as StdMutex};
|
||||
|
||||
#[cfg(feature = "dnssec")]
|
||||
use chrono::Duration;
|
||||
use futures::Future;
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use trust_dns_client::client::Signer;
|
||||
#[cfg(feature = "dnssec")]
|
||||
use trust_dns_client::client::SyncDnssecClient;
|
||||
@@ -30,13 +31,13 @@ use trust_dns_proto::xfer::{DnsMultiplexer, DnsMultiplexerConnect};
|
||||
use trust_dns_server::authority::{Authority, Catalog};
|
||||
|
||||
pub struct TestClientConnection {
|
||||
catalog: Arc<Mutex<Catalog>>,
|
||||
catalog: Arc<StdMutex<Catalog>>,
|
||||
}
|
||||
|
||||
impl TestClientConnection {
|
||||
pub fn new(catalog: Catalog) -> TestClientConnection {
|
||||
TestClientConnection {
|
||||
catalog: Arc::new(Mutex::new(catalog)),
|
||||
catalog: Arc::new(StdMutex::new(catalog)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +65,7 @@ fn test_query_nonet() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let client = SyncClient::new(TestClientConnection::new(catalog));
|
||||
@@ -475,7 +476,7 @@ fn create_sig0_ready_client(mut catalog: Catalog) -> (SyncClient<TestClientConne
|
||||
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
let client = SyncClient::with_signer(TestClientConnection::new(catalog), signer);
|
||||
|
||||
|
@@ -2,8 +2,9 @@
|
||||
|
||||
use std::net::*;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::{Arc, Mutex as StdMutex};
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use tokio::net::TcpStream as TokioTcpStream;
|
||||
use tokio::net::UdpSocket as TokioUdpSocket;
|
||||
use tokio::runtime::Runtime;
|
||||
@@ -228,11 +229,11 @@ where
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let client = AsyncClient::new(stream, sender, None);
|
||||
|
||||
let (client, bg) = io_loop
|
||||
|
@@ -1,25 +1,32 @@
|
||||
use std::net::*;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::{
|
||||
net::*,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex as StdMutex},
|
||||
};
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use trust_dns_proto::op::{NoopMessageFinalizer, Query};
|
||||
use trust_dns_proto::rr::{DNSClass, Name, RData, Record, RecordType};
|
||||
use trust_dns_proto::xfer::{DnsExchange, DnsMultiplexer};
|
||||
use trust_dns_proto::TokioTime;
|
||||
use trust_dns_resolver::caching_client::CachingClient;
|
||||
use trust_dns_resolver::config::LookupIpStrategy;
|
||||
use trust_dns_resolver::error::ResolveError;
|
||||
use trust_dns_resolver::lookup::{Lookup, LookupFuture};
|
||||
use trust_dns_resolver::lookup_ip::LookupIpFuture;
|
||||
use trust_dns_resolver::Hosts;
|
||||
use trust_dns_server::authority::{Authority, Catalog};
|
||||
use trust_dns_server::store::in_memory::InMemoryAuthority;
|
||||
use trust_dns_proto::{
|
||||
op::{NoopMessageFinalizer, Query},
|
||||
rr::{DNSClass, Name, RData, Record, RecordType},
|
||||
xfer::{DnsExchange, DnsMultiplexer},
|
||||
TokioTime,
|
||||
};
|
||||
use trust_dns_resolver::{
|
||||
caching_client::CachingClient,
|
||||
config::LookupIpStrategy,
|
||||
error::ResolveError,
|
||||
lookup::{Lookup, LookupFuture},
|
||||
lookup_ip::LookupIpFuture,
|
||||
Hosts,
|
||||
};
|
||||
use trust_dns_server::{
|
||||
authority::{Authority, Catalog},
|
||||
store::in_memory::InMemoryAuthority,
|
||||
};
|
||||
|
||||
use trust_dns_integration::authority::create_example;
|
||||
use trust_dns_integration::mock_client::*;
|
||||
use trust_dns_integration::TestClientStream;
|
||||
use trust_dns_integration::{authority::create_example, mock_client::*, TestClientStream};
|
||||
|
||||
#[test]
|
||||
fn test_lookup() {
|
||||
@@ -27,11 +34,11 @@ fn test_lookup() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let dns_conn = DnsMultiplexer::new(stream, sender, NoopMessageFinalizer::new());
|
||||
let client = DnsExchange::connect::<_, _, TokioTime>(dns_conn);
|
||||
|
||||
@@ -58,11 +65,11 @@ fn test_lookup_hosts() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let dns_conn = DnsMultiplexer::new(stream, sender, NoopMessageFinalizer::new());
|
||||
|
||||
let client = DnsExchange::connect::<_, _, TokioTime>(dns_conn);
|
||||
@@ -119,11 +126,11 @@ fn test_lookup_ipv4_like() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let dns_conn = DnsMultiplexer::new(stream, sender, NoopMessageFinalizer::new());
|
||||
|
||||
let client = DnsExchange::connect::<_, _, TokioTime>(dns_conn);
|
||||
@@ -152,11 +159,11 @@ fn test_lookup_ipv4_like_fall_through() {
|
||||
let mut catalog = Catalog::new();
|
||||
catalog.upsert(
|
||||
authority.origin().clone(),
|
||||
Box::new(Arc::new(RwLock::new(authority))),
|
||||
Box::new(Arc::new(Mutex::new(authority))),
|
||||
);
|
||||
|
||||
let io_loop = Runtime::new().unwrap();
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(Mutex::new(catalog)));
|
||||
let (stream, sender) = TestClientStream::new(Arc::new(StdMutex::new(catalog)));
|
||||
let dns_conn = DnsMultiplexer::new(stream, sender, NoopMessageFinalizer::new());
|
||||
|
||||
let client = DnsExchange::connect::<_, _, TokioTime>(dns_conn);
|
||||
|
@@ -1,10 +1,11 @@
|
||||
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use futures::lock::Mutex;
|
||||
use futures::{future, Future, FutureExt};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::net::UdpSocket;
|
||||
@@ -264,7 +265,7 @@ fn new_catalog() -> Catalog {
|
||||
let origin = example.origin().clone();
|
||||
|
||||
let mut catalog: Catalog = Catalog::new();
|
||||
catalog.upsert(origin, Box::new(Arc::new(RwLock::new(example))));
|
||||
catalog.upsert(origin, Box::new(Arc::new(Mutex::new(example))));
|
||||
catalog
|
||||
}
|
||||
|
||||
|
@@ -186,7 +186,10 @@ fn test_authorize() {
|
||||
let bytes = message.to_bytes().unwrap();
|
||||
let message = MessageRequest::from_bytes(&bytes).unwrap();
|
||||
|
||||
assert_eq!(authority.authorize(&message), Err(ResponseCode::Refused));
|
||||
assert_eq!(
|
||||
block_on(authority.authorize(&message)),
|
||||
Err(ResponseCode::Refused)
|
||||
);
|
||||
|
||||
// TODO: this will nee to be more complex as additional policies are added
|
||||
// authority.set_allow_update(true);
|
||||
@@ -203,151 +206,174 @@ fn test_prerequisites() {
|
||||
|
||||
// first check the initial negatives, ttl = 0, and the zone is the same
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(86400)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(86400)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::FormErr)
|
||||
);
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_zone)
|
||||
.set_ttl(0)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_zone)
|
||||
.set_ttl(0)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::NotZone)
|
||||
);
|
||||
|
||||
// * ANY ANY empty Name is in use
|
||||
assert!(authority
|
||||
.verify_prerequisites(&[Record::new()
|
||||
assert!(block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::ANY)
|
||||
.set_rr_type(RecordType::ANY)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()])
|
||||
.is_ok());
|
||||
)
|
||||
.is_ok());
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::ANY)
|
||||
.set_rr_type(RecordType::ANY)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::ANY)
|
||||
.set_rr_type(RecordType::ANY)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::NXDomain)
|
||||
);
|
||||
|
||||
// * ANY rrset empty RRset exists (value independent)
|
||||
assert!(authority
|
||||
.verify_prerequisites(&[Record::new()
|
||||
assert!(block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::ANY)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()])
|
||||
.is_ok());
|
||||
)
|
||||
.is_ok());
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::ANY)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::ANY)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::NXRRSet)
|
||||
);
|
||||
|
||||
// * NONE ANY empty Name is not in use
|
||||
assert!(authority
|
||||
.verify_prerequisites(&[Record::new()
|
||||
assert!(block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
.set_rr_type(RecordType::ANY)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()])
|
||||
.is_ok());
|
||||
)
|
||||
.is_ok());
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
.set_rr_type(RecordType::ANY)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
.set_rr_type(RecordType::ANY)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::YXDomain)
|
||||
);
|
||||
|
||||
// * NONE rrset empty RRset does not exist
|
||||
assert!(authority
|
||||
.verify_prerequisites(&[Record::new()
|
||||
assert!(block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone.clone())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()])
|
||||
.is_ok());
|
||||
)
|
||||
.is_ok());
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::NONE)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::NULL(NULL::new()))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::YXRRSet)
|
||||
);
|
||||
|
||||
// * zone rrset rr RRset exists (value dependent)
|
||||
assert!(authority
|
||||
.verify_prerequisites(&[Record::new()
|
||||
assert!(block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 34)))
|
||||
.clone()])
|
||||
.is_ok());
|
||||
)
|
||||
.is_ok());
|
||||
// wrong class
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::CH)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 34)))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::CH)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 34)))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::FormErr)
|
||||
);
|
||||
// wrong Name
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone)
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(not_in_zone)
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::NXRRSet)
|
||||
);
|
||||
// wrong IP
|
||||
assert_eq!(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
|
||||
.clone()],),
|
||||
block_on(
|
||||
authority.verify_prerequisites(&[Record::new()
|
||||
.set_name(authority.origin().clone().into())
|
||||
.set_ttl(0)
|
||||
.set_dns_class(DNSClass::IN)
|
||||
.set_rr_type(RecordType::A)
|
||||
.set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
|
||||
.clone()],)
|
||||
),
|
||||
Err(ResponseCode::NXRRSet)
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user