use lazy_static::lazy_static;
use serde::Serialize;
use thiserror::Error;
use tokio::task::JoinError;
use trust_dns_resolver::error::{ResolveError, ResolveErrorKind};
use trust_dns_resolver::proto::error::{ProtoError, ProtoErrorKind};
use trust_dns_resolver::proto::op::ResponseCode;
static TDR_NAMESERVER_RESPONDED_SERVFAIL: &str = "Nameserver responded with SERVFAIL";
lazy_static! {
pub static ref TDR_QUERY_REFUSED_MSG: String = {
let query_refused = ResponseCode::Refused;
format!("DNS Error: {}", query_refused)
};
}
#[derive(Debug, Clone, Error, Serialize)]
pub enum Error {
#[error("nameserver refused query")]
QueryRefused,
#[error("nameserver responded with server failure")]
ServerFailure,
#[error("request timed out")]
Timeout,
#[error("resolver error: {reason}")]
ResolveError { reason: String },
#[error("protocol error: {reason}")]
ProtoError { reason: String },
#[error("query has been cancelled")]
CancelledError,
#[error("query execution panicked")]
RuntimePanicError,
}
impl From<ResolveError> for Error {
fn from(error: trust_dns_resolver::error::ResolveError) -> Self {
match &error.kind() {
ResolveErrorKind::Msg(msg) if *msg == *TDR_QUERY_REFUSED_MSG => Error::QueryRefused,
ResolveErrorKind::Proto(proto_error) => Self::from(proto_error.clone()),
ResolveErrorKind::Timeout => Error::Timeout,
_ => Error::ResolveError {
reason: error.to_string(),
},
}
}
}
impl From<ProtoError> for Error {
fn from(error: ProtoError) -> Self {
match &error.kind() {
ProtoErrorKind::Message(msg) if *msg == TDR_NAMESERVER_RESPONDED_SERVFAIL => Error::ServerFailure,
ProtoErrorKind::Timeout => Error::Timeout,
_ => Error::ProtoError {
reason: error.to_string(),
},
}
}
}
impl From<JoinError> for Error {
fn from(error: JoinError) -> Self {
if error.is_cancelled() {
return Error::CancelledError;
}
Error::RuntimePanicError
}
}