use bytes::Bytes; use errors::*; use ser::DnsPacketData; use ser::text::{DnsTextData, DnsTextFormatter, next_field}; use std::fmt; use std::io::Cursor; use records::registry::{name_to_type, type_name}; use common_types::types; use std::borrow::Cow; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct Type(pub u16); impl Type { pub fn name(self) -> Cow<'static, str> { if let Some(name) = type_name(self) { Cow::Borrowed(name) } else { Cow::Owned(format!("TYPE{}", self.0)) } } /// defined in RFC 1035 pub fn well_known(self) -> bool { // 0x0001 (A) ... 0x0010 (TXT) are defined in RFC 1035 self.0 >= 0x0001 && self.0 <= 0x0010 } /// require converting to canonical form for DNSSEC (i.e. names /// must be converted to (ASCII) lower case, no compression) /// /// See https://tools.ietf.org/html/rfc4034#section-6.2 (updates RFC 3597). pub fn canonical(self) -> bool { match self { types::NS => true, types::MD => true, types::MF => true, types::CNAME => true, types::SOA => true, types::MB => true, types::MG => true, types::MR => true, types::PTR => true, // types::HINFO => true, // doesn't have a name in data types::MINFO => true, types::MX => true, // types::HINFO => true, // see above, also duplicate in the RFCs types::RP => true, types::AFSDB => true, types::RT => true, types::NSAP_PTR => true, // not listed in the RFCs, but probably should be. types::SIG => true, types::PX => true, types::NXT => true, types::SRV => true, // moved up to match numeric order types::NAPTR => true, types::KX => true, // types::SRV => true, // moved up to match numeric order types::A6 => true, // moved up to match numeric order types::DNAME => true, // types::A6 => true, // moved up to match numeric order types::RRSIG => true, types::NSEC => true, _ => false, } } } impl fmt::Display for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(name) = type_name(*self) { write!(f, "{}", name) } else { write!(f, "TYPE{}", self.0) } } } impl DnsPacketData for Type { fn deserialize(data: &mut Cursor) -> Result { Ok(Type(DnsPacketData::deserialize(data)?)) } } impl DnsTextData for Type { fn dns_parse(data: &mut &str) -> Result { let field = next_field(data)?; if field.starts_with("TYPE") || field.starts_with("type") { if let Ok(t) = field[4..].parse::() { return Ok(Type(t)); } } name_to_type(field).ok_or_else(|| format_err!("unknown type {:?}", field)) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { write!(f, "{}", self) } }