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
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

use std::fmt;
use std::convert::From;
use std::ffi::{NulError, FromBytesWithNulError};
use std::str::Utf8Error;
use crate::Section;

// Taken in part from glibc-2.23/resolv/herror.c h_errlist
#[repr(i32)]
pub enum ResolutionError {
    /// Success
    Success = 0,
    /// Authoritative Answer "Host not found"
    HostNotFound = 1,
    /// Non-Authoritative "Host not found" or SERVERFAIL.
    TryAgain = 2,
    /// Non recoverable errors, FORMERR, REFUSED, NOTIMP.
    NoRecovery = 3,
    /// Valid name, no data record of requested type.
    NoData = 4,
}
impl fmt::Debug for ResolutionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ResolutionError::Success =>  write!(f, "Resolver Error 0 (no error)"),
            ResolutionError::HostNotFound =>  write!(f, "Unknown host"),
            ResolutionError::TryAgain =>  write!(f, "Host name lookup failure"),
            ResolutionError::NoRecovery =>  write!(f, "Unknown server error"),
            ResolutionError::NoData =>  write!(f, "No address associated with name"),
        }
    }
}

pub enum Error {
    /// Name Resolution failed
    Resolver(ResolutionError),
    /// String contains null bytes
    CString(NulError),
    /// Stirng contains null bytes
    CStr(FromBytesWithNulError),
    /// Name service response does not parse
    ParseError,
    /// Section/Index is out of bounds
    NoSuchSectionIndex(Section, usize),
    /// Uncompress Error
    UncompressError,
    /// Result from dn_expand was not null terminated
    Unterminated,
    /// Wrong Resource record type
    WrongRRType,
    /// String is not valid UTF-8
    Utf8(Utf8Error),
    /// Unknown class
    UnknownClass(u16),
}
impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        match *self {
            Error::Resolver(ref e) => write!(f, "{}: {:?}", self.description(), e),
            Error::CString(ref e) => write!(f, "Name supplied contains a null byte at \
                                                position {}", e.nul_position()),
            Error::CStr(ref e) => write!(f, "{}: {:?}", self.description(), e),
            Error::NoSuchSectionIndex(s,i) => write!(f, "No such section index \
                                                         (section={:?}, index={})",
                                                     s, i),
            Error::Utf8(ref e) => write!(f, "{}: {:?}", self.description(), e),
            Error::UnknownClass(u) => write!(f, "{}: {}", self.description(), u),
            _ => write!(f, "{}", self.description()),
        }
    }
}
impl Error {
    fn description(&self) -> &str
    {
        match *self {
            Error::Resolver(_) => "Name Resolution failed",
            Error::CString(_) => "Name supplied contains a null byte",
            Error::CStr(_) => "CStr failed",
            Error::ParseError => "Name service response does not parse",
            Error::NoSuchSectionIndex(_,_) => "No such section index",
            Error::UncompressError => "Error uncompressing domain name",
            Error::Unterminated => "Result from dn_expand was not null terminated",
            Error::WrongRRType => "Wrong Resource Record type",
            Error::Utf8(_) => "UTF-8 error",
            Error::UnknownClass(_) => "Unknown class",
        }
    }

}
impl ::std::error::Error for Error {
    fn cause(&self) -> Option<&dyn (::std::error::Error)>
    {
        match *self {
            Error::CString(ref e) => Some(e),
            Error::Utf8(ref e) => Some(e),
            _ => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Resolver(ref e) => write!(f, "{}: {:?}", self.description(), e),
            Error::CString(ref e) => write!(f, "Name supplied contains a null byte at \
                                                position {}", e.nul_position()),
            Error::CStr(ref e) => write!(f, "{}: {:?}", self.description(), e),
            Error::NoSuchSectionIndex(s,i) => write!(f, "No such section index \
                                                         (section={:?}, index={})",
                                                     s, i),
            Error::Utf8(ref e) => write!(f, "{}: {}", self.description(), e),
            Error::UnknownClass(u) => write!(f, "{}: {}", self.description(), u),
            _ =>  write!(f, "{}", self.description()),
        }
    }
}

impl From<ResolutionError> for Error {
    fn from(err: ResolutionError) -> Error {
        Error::Resolver( err )
    }
}
impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Error {
        Error::Utf8( err )
    }
}
impl From<FromBytesWithNulError> for Error {
    fn from(err: FromBytesWithNulError) -> Error {
        Error::CStr( err )
    }
}