resolver compiling

This commit is contained in:
Benjamin Fry 2017-10-08 12:51:04 -07:00
parent 6f8927a2b2
commit 48545b6cf3
14 changed files with 125 additions and 1130 deletions

View File

@ -5,9 +5,22 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## 0.12.1
### Added
- TRust-DNS Proto crate to separate server management from base operations
- TRust-DNS Util crate for dnssec management tools (@briansmith)
- Integration tests for Server to validate all supported DNSSec key types
### Changed
- DNSKEY is now self-signed
- Internal API changes to `client` calling into `proto` for actual implementations
- Large refactoring of internal APIs to more cleanly support \*ring\* and OpenSSL features (@briansmith)
- `ClientHandle::send` moved to `trust_dns_proto::DnsHandle::send` (internal API)
### Fixed
- Server signing issues when loading from persistence
## 0.12.0

1
Cargo.lock generated
View File

@ -1290,6 +1290,7 @@ dependencies = [
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.12.0",
"trust-dns-proto 0.1.0",
]
[[package]]

View File

@ -65,7 +65,7 @@ pub trait Client<C: ClientHandle> {
name: &domain::Name,
query_class: DNSClass,
query_type: RecordType,
) -> ProtoResult<Message> {
) -> ClientResult<Message> {
self.get_io_loop().run(self.get_client_handle().query(
name.clone(),
query_class,
@ -498,7 +498,7 @@ impl SecureSyncClient {
query_name: &domain::Name,
query_class: DNSClass,
query_type: RecordType,
) -> ProtoResult<Message> {
) -> ClientResult<Message> {
self.get_io_loop().run(self.get_client_handle().query(
query_name.clone(),
query_class,

View File

@ -405,9 +405,10 @@ pub struct BasicClientHandle {
}
impl DnsHandle for BasicClientHandle {
// FIXME: this is a type change, generify DnsHandle Result...
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ProtoError>> {
self.message_sender.send(message)
type Error = ClientError;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
Box::new(self.message_sender.send(message).map_err(ClientError::from))
}
}
@ -418,7 +419,7 @@ impl ClientHandle for BasicClientHandle {
}
/// A trait for implementing high level functions of DNS.
pub trait ClientHandle: Clone + DnsHandle {
pub trait ClientHandle: Clone + DnsHandle<Error = ClientError> {
/// Ony returns true if and only if this client is validating DNSSec.
///
/// If the ClientHandle impl is wrapping other clients, then the correct option is to delegate the question to the wrapped client.
@ -434,7 +435,7 @@ pub trait ClientHandle: Clone + DnsHandle {
/// # Arguments
///
/// * `query` - the query to lookup
fn lookup(&mut self, query: Query) -> Box<Future<Item = Message, Error = ProtoError>> {
fn lookup(&mut self, query: Query) -> Box<Future<Item = Message, Error = ClientError>> {
debug!("querying: {} {:?}", query.name(), query.query_type());
// build the message
@ -455,7 +456,7 @@ pub trait ClientHandle: Clone + DnsHandle {
edns.set_version(0);
}
Box::new(self.send(message).map_err(Into::into))
self.send(message)
}
// FIXME: changed return type
@ -474,7 +475,7 @@ pub trait ClientHandle: Clone + DnsHandle {
name: domain::Name,
query_class: DNSClass,
query_type: RecordType,
) -> Box<Future<Item = Message, Error = ProtoError>> {
) -> Box<Future<Item = Message, Error = ClientError>> {
let mut query = Query::query(name, query_type);
query.set_query_class(query_class);
self.lookup(query)

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@ use op::{Message, Query};
pub struct MemoizeClientHandle<H: ClientHandle> {
client: H,
active_queries:
Rc<RefCell<HashMap<Query, RcFuture<Box<Future<Item = Message, Error = ProtoError>>>>>>,
Rc<RefCell<HashMap<Query, RcFuture<Box<Future<Item = Message, Error = ClientError>>>>>>,
}
impl<H> MemoizeClientHandle<H>
@ -48,13 +48,14 @@ impl<H> DnsHandle for MemoizeClientHandle<H>
where
H: ClientHandle,
{
// FIXME: this is a type change, generify DnsHandle Result...
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ProtoError>> {
type Error = ClientError;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
let query = message.queries().first().expect("no query!").clone();
if let Some(rc_future) = self.active_queries.borrow().get(&query) {
// FIXME check TTLs?
return Box::new(rc_future.clone());
return Box::new(rc_future.clone().map_err(ClientError::from));
}
// check if there are active queries
@ -62,7 +63,7 @@ where
let map = self.active_queries.borrow();
let request = map.get(&query);
if request.is_some() {
return Box::new(request.unwrap().clone());
return Box::new(request.unwrap().clone().map_err(ClientError::from));
}
}

View File

@ -46,8 +46,10 @@ impl<H> DnsHandle for RetryClientHandle<H>
where
H: ClientHandle + 'static,
{
type Error = ClientError;
// FIXME: this is a type change, generify DnsHandle Result...
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ProtoError>> {
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
// need to clone here so that the retry can resend if necessary...
// obviously it would be nice to be lazy about this...
let future = self.client.send(message.clone());
@ -74,7 +76,7 @@ where
struct RetrySendFuture<H: ClientHandle> {
message: Message,
client: H,
future: Box<Future<Item = Message, Error = ProtoError>>,
future: Box<Future<Item = Message, Error = ClientError>>,
remaining_attempts: usize,
}
@ -83,7 +85,7 @@ where
H: ClientHandle,
{
type Item = Message;
type Error = ProtoError;
type Error = ClientError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
// loop over the future, on errors, spawn a new future

View File

@ -98,12 +98,14 @@ impl<H> DnsHandle for SecureClientHandle<H>
where
H: ClientHandle,
{
type Error = ClientError;
// FIXME: this is a type change, generify DnsHandle Result...
fn send(&mut self, mut message: Message) -> Box<Future<Item = Message, Error = ProtoError>> {
fn send(&mut self, mut message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
// backstop, this might need to be configurable at some point
if self.request_depth > 20 {
return Box::new(failed(
ProtoErrorKind::Message("exceeded max validation depth")
ClientErrorKind::Message("exceeded max validation depth")
.into(),
));
}
@ -169,7 +171,7 @@ where
if !verify_nsec(&query, nsecs) {
// TODO change this to remove the NSECs, like we do for the others?
return Err(
ProtoErrorKind::Message(
ClientErrorKind::Message(
"could not validate nxdomain \
with NSEC",
).into(),
@ -199,7 +201,7 @@ where
/// A future to verify all RRSets in a returned Message.
struct VerifyRrsetsFuture {
message_result: Option<Message>,
rrsets: SelectAll<Box<Future<Item = Rrset, Error = ProtoError>>>,
rrsets: SelectAll<Box<Future<Item = Rrset, Error = ClientError>>>,
verified_rrsets: HashSet<(domain::Name, RecordType)>,
}
@ -209,7 +211,7 @@ fn verify_rrsets<H>(
client: SecureClientHandle<H>,
message_result: Message,
dns_class: DNSClass,
) -> Box<Future<Item = Message, Error = ProtoError>>
) -> Box<Future<Item = Message, Error = ClientError>>
where
H: ClientHandle,
{
@ -239,7 +241,7 @@ where
message_result.take_additionals();
return Box::new(failed(
ProtoErrorKind::Message("no results to verify").into(),
ClientErrorKind::Message("no results to verify").into(),
));
}
@ -247,7 +249,7 @@ where
// collect all the rrsets to verify
// TODO: is there a way to get rid of this clone() safely?
let mut rrsets: Vec<Box<Future<Item = Rrset, Error = ProtoError>>> =
let mut rrsets: Vec<Box<Future<Item = Rrset, Error = ClientError>>> =
Vec::with_capacity(rrset_types.len());
for (name, record_type) in rrset_types {
// TODO: should we evaluate the different sections (answers and name_servers) separately?
@ -306,11 +308,11 @@ where
impl Future for VerifyRrsetsFuture {
type Item = Message;
type Error = ProtoError;
type Error = ClientError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if self.message_result.is_none() {
return Err(ProtoErrorKind::Message("message is none").into());
return Err(ClientErrorKind::Message("message is none").into());
}
// loop through all the rrset evaluations, filter all the rrsets in the Message
@ -410,7 +412,7 @@ fn verify_rrset<H>(
client: SecureClientHandle<H>,
rrset: Rrset,
rrsigs: Vec<Record>,
) -> Box<Future<Item = Rrset, Error = ProtoError>>
) -> Box<Future<Item = Rrset, Error = ClientError>>
where
H: ClientHandle,
{
@ -451,7 +453,7 @@ where
fn verify_dnskey_rrset<H>(
mut client: SecureClientHandle<H>,
rrset: Rrset,
) -> Box<Future<Item = Rrset, Error = ProtoError>>
) -> Box<Future<Item = Rrset, Error = ClientError>>
where
H: ClientHandle,
{
@ -537,7 +539,7 @@ where
Ok(rrset)
} else {
Err(
ProtoErrorKind::Message("Could not validate all DNSKEYs").into(),
ClientErrorKind::Message("Could not validate all DNSKEYs").into(),
)
}
});
@ -613,7 +615,7 @@ fn verify_default_rrset<H>(
client: SecureClientHandle<H>,
rrset: Rrset,
rrsigs: Vec<Record>,
) -> Box<Future<Item = Rrset, Error = ProtoError>>
) -> Box<Future<Item = Rrset, Error = ClientError>>
where
H: ClientHandle,
{
@ -669,7 +671,7 @@ where
}
})
.next()
.ok_or(ProtoErrorKind::Message("self-signed dnskey is invalid").into()),
.ok_or(ClientErrorKind::Message("self-signed dnskey is invalid").into()),
).map(move |rrset| {
Rc::try_unwrap(rrset).expect("unable to unwrap Rc")
}),
@ -714,7 +716,7 @@ where
}
)
.map(|_| rrset)
.ok_or(ProtoErrorKind::Message("validation failed").into())
.ok_or(ClientErrorKind::Message("validation failed").into())
)
})
.collect::<Vec<_>>();
@ -722,7 +724,7 @@ where
// if there are no available verifications, then we are in a failed state.
if verifications.is_empty() {
return Box::new(failed(
ProtoErrorKind::Msg(format!(
ClientErrorKind::Msg(format!(
"no RRSIGs available for \
validation: {}, {:?}",
rrset.name,

View File

@ -415,7 +415,9 @@ pub struct BasicDnsHandle {
}
impl DnsHandle for BasicDnsHandle {
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ProtoError>> {
type Error = ProtoError;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
let (complete, receiver) = oneshot::channel();
let message_sender: &mut _ = &mut self.message_sender;
@ -447,6 +449,8 @@ impl DnsHandle for BasicDnsHandle {
/// A trait for implementing high level functions of DNS.
pub trait DnsHandle: Clone {
type Error;
// FIXME: make result generic...
/// Send a message via the channel in the client
///
@ -455,5 +459,5 @@ pub trait DnsHandle: Clone {
/// * `message` - the fully constructed Message to send, note that most implementations of
/// will most likely be required to rewrite the QueryId, do no rely on that as
/// being stable.
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ProtoError>>;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>>;
}

View File

@ -51,6 +51,7 @@ lru-cache = "^0.1.1"
regex = "0.2.1"
tokio-core = "^0.1"
trust-dns = { version = "^0.12.0", path = "../client" }
trust-dns-proto = { version = "^0.1", path = "../proto" }
[target.'cfg(all(windows, target_arch = "x86_64"))'.dependencies]
ipconfig = "^0.1.1"

View File

@ -132,6 +132,7 @@ extern crate log;
extern crate lru_cache;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_proto;
#[cfg(all(target_os = "windows", target_pointer_width = "64"))]
extern crate ipconfig;

View File

@ -22,6 +22,7 @@ use trust_dns::error::ClientError;
use trust_dns::op::{Message, Query};
use trust_dns::rr::{Name, RecordType, RData};
use trust_dns::rr::rdata;
use trust_dns_proto::DnsHandle;
use lookup_state::CachingClient;
use name_server_pool::{ConnectionProvider, NameServerPool, StandardConnection};
@ -82,13 +83,9 @@ pub enum LookupEither<C: ClientHandle + 'static, P: ConnectionProvider<ConnHandl
Secure(SecureClientHandle<RetryClientHandle<NameServerPool<C, P>>>),
}
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> ClientHandle for LookupEither<C, P> {
fn is_verifying_dnssec(&self) -> bool {
match *self {
LookupEither::Retry(ref c) => c.is_verifying_dnssec(),
LookupEither::Secure(ref c) => c.is_verifying_dnssec(),
}
}
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> DnsHandle for LookupEither<C, P> {
// FIXME: make this a ResolverError
type Error = ClientError;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ClientError>> {
match *self {
@ -98,6 +95,15 @@ impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> ClientHandle for Lo
}
}
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> ClientHandle for LookupEither<C, P> {
fn is_verifying_dnssec(&self) -> bool {
match *self {
LookupEither::Retry(ref c) => c.is_verifying_dnssec(),
LookupEither::Secure(ref c) => c.is_verifying_dnssec(),
}
}
}
/// The Future returned from ResolverFuture when performing a lookup.
pub type LookupFuture = InnerLookupFuture<LookupEither<BasicClientHandle, StandardConnection>>;
@ -306,18 +312,22 @@ pub mod tests {
messages: Arc<Mutex<Vec<ClientResult<Message>>>>,
}
impl ClientHandle for MockClientHandle {
fn is_verifying_dnssec(&self) -> bool {
false
}
impl DnsHandle for MockClientHandle {
type Error = ClientError;
fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = ClientError>> {
fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
Box::new(future::result(
self.messages.lock().unwrap().pop().unwrap_or(empty()),
))
}
}
impl ClientHandle for MockClientHandle {
fn is_verifying_dnssec(&self) -> bool {
false
}
}
pub fn v4_message() -> ClientResult<Message> {
let mut message = Message::new();
message.insert_answers(vec![

View File

@ -292,6 +292,7 @@ pub mod tests {
use trust_dns::error::*;
use trust_dns::op::Message;
use trust_dns::rr::{Name, Record, RData, RecordType};
use trust_dns_proto::DnsHandle;
use super::*;
@ -300,18 +301,22 @@ pub mod tests {
messages: Arc<Mutex<Vec<ClientResult<Message>>>>,
}
impl ClientHandle for MockClientHandle {
fn is_verifying_dnssec(&self) -> bool {
false
}
impl DnsHandle for MockClientHandle {
type Error = ClientError;
fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = ClientError>> {
fn send(&mut self, _: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
Box::new(future::result(
self.messages.lock().unwrap().pop().unwrap_or(empty()),
))
}
}
impl ClientHandle for MockClientHandle {
fn is_verifying_dnssec(&self) -> bool {
false
}
}
pub fn v4_message() -> ClientResult<Message> {
let mut message = Message::new();
message.insert_answers(vec![

View File

@ -20,7 +20,7 @@ use trust_dns::client::{BasicClientHandle, ClientFuture, ClientHandle};
use trust_dns::op::{Edns, Message, ResponseCode};
use trust_dns::udp::UdpClientStream;
use trust_dns::tcp::TcpClientStream;
// use trust_dns::tls::TlsClientStream;
use trust_dns_proto::DnsHandle;
use config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts};
@ -210,7 +210,7 @@ pub struct NameServer<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> {
config: NameServerConfig,
options: ResolverOpts,
client: C,
// FIXME: switch to FuturesMutex? (Mutex will have some undesireable locking)
// TODO: switch to FuturesMutex? (Mutex will have some undesireable locking)
stats: Arc<Mutex<NameServerStats>>,
reactor: Handle,
phantom: PhantomData<P>,
@ -314,13 +314,10 @@ impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> NameServer<C, P> {
}
}
// TODO: there needs to be some way of customizing the connection based on EDNS options from the server side...
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> ClientHandle for NameServer<C, P> {
fn is_verifying_dnssec(&self) -> bool {
self.client.is_verifying_dnssec()
}
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> DnsHandle for NameServer<C, P> {
type Error = ClientError;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ClientError>> {
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
// if state is failed, return future::err(), unless retry delay expired...
if let Err(error) = self.try_reconnect() {
return Box::new(future::err(error));
@ -363,6 +360,13 @@ impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> ClientHandle for Na
}
}
// TODO: there needs to be some way of customizing the connection based on EDNS options from the server side...
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> ClientHandle for NameServer<C, P> {
fn is_verifying_dnssec(&self) -> bool {
self.client.is_verifying_dnssec()
}
}
impl<C: ClientHandle, P: ConnectionProvider<ConnHandle = C>> Ord for NameServer<C, P> {
/// Custom implementation of Ord for NameServer which incorporates the performance of the connection into it's ranking
fn cmp(&self, other: &Self) -> Ordering {
@ -476,16 +480,14 @@ impl<C: ClientHandle + 'static, P: ConnectionProvider<ConnHandle = C> + 'static>
}
}
impl<C: ClientHandle + 'static, P: ConnectionProvider<ConnHandle = C> + 'static> ClientHandle
for NameServerPool<C, P> {
fn is_verifying_dnssec(&self) -> bool {
// don't pull a lock on this
// it is expected that a validating client will wrap this, as opposed to the other direction.
// so pool -> nameserver -> basic_client_handle will always return false anyway
false
}
impl<C, P> DnsHandle for NameServerPool<C, P>
where
C: ClientHandle + 'static,
P: ConnectionProvider<ConnHandle = C> + 'static,
{
type Error = ClientError;
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = ClientError>> {
fn send(&mut self, message: Message) -> Box<Future<Item = Message, Error = Self::Error>> {
let datagram_conns = self.datagram_conns.clone();
let stream_conns1 = self.stream_conns.clone();
let stream_conns2 = self.stream_conns.clone();
@ -509,6 +511,19 @@ impl<C: ClientHandle + 'static, P: ConnectionProvider<ConnHandle = C> + 'static>
}
}
impl<C, P> ClientHandle for NameServerPool<C, P>
where
C: ClientHandle + 'static,
P: ConnectionProvider<ConnHandle = C> + 'static,
{
fn is_verifying_dnssec(&self) -> bool {
// don't pull a lock on this
// it is expected that a validating client will wrap this, as opposed to the other direction.
// so pool -> nameserver -> basic_client_handle will always return false anyway
false
}
}
enum TrySend<C: ClientHandle + 'static, P: ConnectionProvider<ConnHandle = C> + 'static> {
Lock {
conns: Arc<Mutex<BinaryHeap<NameServer<C, P>>>>,