adjust interfaces for recursor

This commit is contained in:
Benjamin Fry 2022-03-05 17:08:09 -08:00
parent ab0094a4ff
commit 47ac8b39f7
4 changed files with 202 additions and 11 deletions

View File

@ -0,0 +1,160 @@
// Copyright 2015-2020 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.
//! Error types for the crate
#![deny(missing_docs)]
use std::{fmt, io, sync};
use enum_as_inner::EnumAsInner;
use thiserror::Error;
#[cfg(feature = "backtrace")]
use crate::proto::{trace, ExtBacktrace};
use crate::{
proto::error::{ProtoError, ProtoErrorKind},
resolver::error::{ResolveError, ResolveErrorKind},
};
/// The error kind for errors that get returned in the crate
#[derive(Debug, EnumAsInner, Error)]
#[non_exhaustive]
pub enum ErrorKind {
/// An error with an arbitrary message, referenced as &'static str
#[error("{0}")]
Message(&'static str),
/// An error with an arbitrary message, stored as String
#[error("{0}")]
Msg(String),
/// An error got returned from IO
#[error("io error: {0}")]
Io(#[from] std::io::Error),
/// An error got returned by the trust-dns-proto crate
#[error("proto error: {0}")]
Proto(#[from] ProtoError),
/// An error got returned by the trust-dns-proto crate
#[error("proto error: {0}")]
Resolve(#[from] ResolveError),
/// A request timed out
#[error("request timed out")]
Timeout,
}
/// The error type for errors that get returned in the crate
#[derive(Error, Clone, Debug)]
#[non_exhaustive]
pub struct Error {
/// Kind of error that ocurred
pub kind: Box<ErrorKind>,
/// Backtrace to the source of the error
#[cfg(feature = "backtrace")]
pub backtrack: Option<ExtBacktrace>,
}
impl Error {
/// Get the kind of the error
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if::cfg_if! {
if #[cfg(feature = "backtrace")] {
if let Some(ref backtrace) = self.backtrack {
fmt::Display::fmt(&self.kind, f)?;
fmt::Debug::fmt(backtrace, f)
} else {
fmt::Display::fmt(&self.kind, f)
}
} else {
fmt::Display::fmt(&self.kind, f)
}
}
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Self {
kind: Box::new(kind),
#[cfg(feature = "backtrace")]
backtrack: trace!(),
}
}
}
impl From<&'static str> for Error {
fn from(msg: &'static str) -> Self {
ErrorKind::Message(msg).into()
}
}
impl From<String> for Error {
fn from(msg: String) -> Self {
ErrorKind::Msg(msg).into()
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
match e.kind() {
io::ErrorKind::TimedOut => ErrorKind::Timeout.into(),
_ => ErrorKind::from(e).into(),
}
}
}
impl From<Error> for io::Error {
fn from(e: Error) -> Self {
match *e.kind() {
ErrorKind::Timeout => Self::new(io::ErrorKind::TimedOut, e),
_ => Self::new(io::ErrorKind::Other, e),
}
}
}
impl From<Error> for String {
fn from(e: Error) -> Self {
e.to_string()
}
}
#[cfg(feature = "wasm-bindgen")]
#[cfg_attr(docsrs, doc(cfg(feature = "wasm-bindgen")))]
impl From<Error> for wasm_bindgen_crate::JsValue {
fn from(e: Error) -> Self {
js_sys::Error::new(&e.to_string()).into()
}
}
impl Clone for ErrorKind {
fn clone(&self) -> Self {
use self::ErrorKind::*;
match *self {
Message(msg) => Message(msg),
Msg(ref msg) => Msg(msg.clone()),
Io(ref io) => Self::from(std::io::Error::from(io.kind())),
Proto(ref proto) => Self::from(proto.clone()),
Resolve(ref resolve) => Self::from(resolve.clone()),
Timeout => Self::Timeout,
}
}
}
/// A trait marking a type which implements From<Error> and
/// std::error::Error types as well as Clone + Send
pub trait FromError: From<Error> + std::error::Error + Clone {}
impl<E> FromError for E where E: From<Error> + std::error::Error + Clone {}

View File

@ -19,7 +19,11 @@
#![recursion_limit = "2048"]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod error;
mod recursor;
pub use error::{Error, ErrorKind};
pub use recursor::Recursor;
pub use trust_dns_proto as proto;
pub use trust_dns_resolver as resolver;
pub use trust_dns_resolver::config::NameServerConfig;

View File

@ -1,15 +1,17 @@
use std::fmt;
use std::{fmt, time::Instant};
use log::debug;
use trust_dns_proto::rr::RecordType;
use trust_dns_proto::rr::{RecordSet, RecordType};
use trust_dns_resolver::{
config::{NameServerConfig, NameServerConfigGroup, ResolverConfig, ResolverOpts},
config::{NameServerConfigGroup, ResolverConfig, ResolverOpts},
error::ResolveError,
lookup::Lookup,
IntoName, Name, TokioAsyncResolver,
name_server::NameServerPool,
IntoName, Name, TokioAsyncResolver, TokioConnection, TokioConnectionProvider,
};
use crate::Error;
/// A top down recursive resolver which operates off a list of "hints", this is often the root nodes.
pub struct Recursor {
hints: TokioAsyncResolver,
@ -35,7 +37,8 @@ impl Recursor {
/// Permform a recursive resolution
///
/// [https://datatracker.ietf.org/doc/html/rfc1034#section-5.3.3](RFC 1034), Domain Concepts and Facilities, November 1987
/// [RFC 1034](https://datatracker.ietf.org/doc/html/rfc1034#section-5.3.3), Domain Concepts and Facilities, November 1987
///
/// ```text
/// 5.3.3. Algorithm
///
@ -197,11 +200,12 @@ impl Recursor {
&self,
domain: N,
ty: RecordType,
request_time: Instant,
) -> Result<Lookup, ResolveError> {
let domain = domain.into_name()?;
// wild guess on number fo lookups needed
let mut lookups = Vec::<RecursiveLookup>::with_capacity(10);
let mut lookups = Vec::<RecursiveQuery>::with_capacity(10);
lookups.push((domain.clone(), ty).into());
// collect all the nameservers we need.
@ -222,14 +226,23 @@ impl Recursor {
todo!();
}
async fn lookup(
&self,
domain: &Name,
ty: RecordType,
ns: &NameServerPool<TokioConnection, TokioConnectionProvider>,
) -> Result<RecordSet, Error> {
unimplemented!()
}
}
struct RecursiveLookup {
struct RecursiveQuery {
name: Name,
ty: RecordType,
}
impl From<(Name, RecordType)> for RecursiveLookup {
impl From<(Name, RecordType)> for RecursiveQuery {
fn from(name_ty: (Name, RecordType)) -> Self {
Self {
name: name_ty.0,
@ -238,7 +251,7 @@ impl From<(Name, RecordType)> for RecursiveLookup {
}
}
impl fmt::Display for RecursiveLookup {
impl fmt::Display for RecursiveQuery {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "({},{})", self.name, self.ty)
}
@ -254,3 +267,8 @@ fn recursor_opts() -> ResolverOpts {
options
}
enum RecursiveLookup {
Found(RecordSet),
Forward(RecordSet),
}

View File

@ -20,7 +20,11 @@
unreachable_pub
)]
use std::net::{IpAddr, SocketAddr};
use std::{
net::{IpAddr, SocketAddr},
path::{Path, PathBuf},
time::Instant,
};
use clap::Parser;
use console::style;
@ -85,6 +89,10 @@ struct Opts {
/// Enable error logging
#[clap(long)]
error: bool,
/// Path to a hints file
#[clap(short = 'f', long)]
hints: PathBuf,
}
/// Run the resolve programf
@ -176,7 +184,8 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
ty = style(ty).yellow(),
);
let lookup = recursor.resolve(name.to_string(), ty).await?;
let now = Instant::now();
let lookup = recursor.resolve(name.to_string(), ty, now).await?;
// report response, TODO: better display of errors
println!(