Move to async-trait for server to simplify function calls

This commit is contained in:
Benjamin Fry
2021-09-05 11:00:16 -07:00
parent 6dde9938d9
commit b8ad0d68ca
27 changed files with 631 additions and 669 deletions

1
Cargo.lock generated
View File

@@ -1676,6 +1676,7 @@ dependencies = [
name = "trust-dns-integration"
version = "0.21.0-alpha.2"
dependencies = [
"async-trait",
"chrono",
"env_logger",
"futures",

View File

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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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 {

View File

@@ -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};

View File

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

View File

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

View File

@@ -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(),

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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())),
}
}
}

View File

@@ -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())
}
}

View File

@@ -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
}
}

View File

@@ -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) {

View File

@@ -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]) {

View File

@@ -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"

View File

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

View File

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

View File

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

View File

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

View File

@@ -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

View File

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

View File

@@ -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
}

View File

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