1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Copyright 2017-2021 Lukas Pustina <lukas@pustina.de>
//
// 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 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! {
    // cf. trust-dns-proto-0.19.5/src/op/response_code.rs:157
    // cf. trust-dns-resolver-0.19.5/src/lookup_state.rs:174
    pub static ref TDR_QUERY_REFUSED_MSG: String = {
        let query_refused = ResponseCode::Refused;
        format!("DNS Error: {}", query_refused)
    };
    // cf. trust-dns-resolver-0.19.5/src/name_server/name_server.rs:144
}

#[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() {
            // Unfortunately, trust-dns-resolver does not provided types errors for some cases, so we have to look at the error msg
            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() {
            // Unfortunately, trust-dns-resolver does not provided types errors for some cases, so we have to look at the error msg
            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
    }
}