This commit is contained in:
Stefan Bühler 2017-12-26 22:23:47 +01:00
parent e0f597ba9c
commit c4c84bd887
8 changed files with 510 additions and 191 deletions

View File

@ -1,3 +1,5 @@
//! Types and constants for DNS CLASSes
use bytes::Bytes; use bytes::Bytes;
use errors::*; use errors::*;
use ser::DnsPacketData; use ser::DnsPacketData;
@ -6,13 +8,15 @@ use std::fmt;
use std::io::Cursor; use std::io::Cursor;
use std::borrow::Cow; use std::borrow::Cow;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] /// CLASS Internet
pub struct Class(pub u16);
pub const IN : Class = Class(KnownClass::IN as u16); pub const IN : Class = Class(KnownClass::IN as u16);
/// CLASS "Chaos"
pub const CH : Class = Class(KnownClass::CH as u16); pub const CH : Class = Class(KnownClass::CH as u16);
/// CLASS "Hesiod"
pub const HS : Class = Class(KnownClass::HS as u16); pub const HS : Class = Class(KnownClass::HS as u16);
/// QCLASS NONE
pub const NONE : Class = Class(KnownQClass::NONE as u16); pub const NONE : Class = Class(KnownQClass::NONE as u16);
/// QCLASS "*" (ANY)
pub const ANY : Class = Class(KnownQClass::ANY as u16); pub const ANY : Class = Class(KnownQClass::ANY as u16);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
@ -20,9 +24,12 @@ pub const ANY : Class = Class(KnownQClass::ANY as u16);
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum KnownClass { pub enum KnownClass {
// try to list "original" rfc // try to list "original" rfc
/// CLASS Internet
IN = 0x0001, // RFC 1035 IN = 0x0001, // RFC 1035
// CS = 0x0002, // "CSNET" // CS = 0x0002, // "CSNET" (not just obsolete; unassigned in the IANA registry)
/// CLASS "Chaos"
CH = 0x0003, // "Chaos" CH = 0x0003, // "Chaos"
/// CLASS "Hesiod"
HS = 0x0004, // "Hesiod" HS = 0x0004, // "Hesiod"
} }
@ -31,83 +38,141 @@ pub enum KnownClass {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum KnownQClass { pub enum KnownQClass {
// try to list "original" rfc // try to list "original" rfc
/// QCLASS NONE
NONE = 0x00fe, // RFC 2136 NONE = 0x00fe, // RFC 2136
ANY = 0x00ff, // RFC 1035: "*" /// QCLASS "*" (ANY)
ANY = 0x00ff, // RFC 1035
} }
/// DNS CLASS
///
/// Originally QCLASS was a superset of CLASS; RFC 6895 now defines:
///
/// > There are currently two subcategories of DNS CLASSes: normal,
/// > data-containing classes; and QCLASSes that are only meaningful in
/// > queries or updates.
///
/// ## `ANY`
///
/// QTYPE 255 either (rules from RFC 6895):
///
/// - doesn't have a mnemonic, violating the existence rule
/// - has "*" as mnemonic, violating the formatting rule
/// - has "ANY" as mnemonic, violating the uniquess rule (class ANY)
///
/// Solution: use "ANY" for type 255, don't accept "ANY" as class in
/// places a type could be given too: `*_without_any`.
///
/// The QCLASS `ANY` is mostly useless anyway and shouldn't be used in
/// normal queries.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Class(pub u16);
impl Class { impl Class {
pub fn name(self) -> Cow<'static, str> { /// map to `KnownQClass`
Cow::Borrowed(match self { pub fn known_qclass(self) -> Option<KnownQClass> {
Some(match self {
NONE => KnownQClass::NONE,
ANY => KnownQClass::ANY,
_ => return None,
})
}
/// whether class is known to be a QCLASS
pub fn is_known_qclass(self) -> bool {
self.known_qclass().is_some()
}
/// name for CLASS if known
///
/// Known CLASSes are represented using their known mnemonic, others
/// return None.
pub fn known_name(self) -> Option<&'static str> {
Some(match self {
IN => "IN", IN => "IN",
CH => "CH", CH => "CH",
HS => "HS", HS => "HS",
NONE => "NONE", NONE => "NONE",
ANY => "ANY", ANY => "ANY",
_ => return Cow::Owned(self.generic_name()), _ => return None,
}) })
} }
/// uses generic name for QCLASS values (`is_qclass`) /// name for CLASS
pub fn class_name(self) -> Cow<'static, str> {
if self.is_qclass() {
Cow::Owned(self.generic_name())
} else {
self.name()
}
}
/// QCLASS names can overlap with (Q)TYPE names
/// ///
/// classes unknown to this implementation never count as QCLASS, /// Known CLASSes are represented using their known mnemonic, others
/// but they also are only represented using the generic "CLASS..." /// using the "CLASS..." syntax (RFC 3597).
/// names, which don't overlap with (Q)TYPE names. pub fn name(self) -> Cow<'static, str> {
pub fn is_qclass(self) -> bool { match self.known_name() {
match self { Some(n) => Cow::Borrowed(n),
NONE => true, None => Cow::Owned(self.generic_name()),
ANY => true,
_ => false,
} }
} }
pub fn from_name(name: &str) -> Option<Self> { /// similar to `name`, but returns "CLASS255" for the `ANY` class
use std::ascii::AsciiExt; pub fn name_without_any(self) -> Cow<'static, str> {
if let Some(n) = Self::class_from_name(name) { return Some(n); } match self {
// explicit QCLASS names ANY => Cow::Borrowed("CLASS255"),
if name.eq_ignore_ascii_case("NONE") { return Some(NONE); } _ => self.name(),
if name.eq_ignore_ascii_case("ANY") { return Some(ANY); } }
None
} }
/// similar to `from_name`, but doesn't accept QCLASS names (it /// generic name "CLASS..."
/// always accepts "CLASS..." names though, even if they are known to pub fn generic_name(self) -> String {
/// be of type QCLASS) let mut result = String::new();
pub fn class_from_name(name: &str) -> Option<Self> { self.write_generic_name(&mut result).unwrap();
result
}
/// directly write generic name "CLASS..." to some target
pub fn write_generic_name<W: fmt::Write>(self, w: &mut W) -> fmt::Result {
write!(w, "CLASS{}", self.0)
}
/// only parse known names (mnemonics), but not `ANY`
///
/// Avoids conflict with parsing RRTYPE mnemonics.
pub fn from_known_name_without_any(name: &str) -> Option<Self> {
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
if name.eq_ignore_ascii_case("IN") { return Some(IN); } if name.eq_ignore_ascii_case("IN") { return Some(IN); }
if name.eq_ignore_ascii_case("CH") { return Some(CH); } if name.eq_ignore_ascii_case("CH") { return Some(CH); }
if name.eq_ignore_ascii_case("HS") { return Some(HS); } if name.eq_ignore_ascii_case("HS") { return Some(HS); }
if name.as_bytes()[0..5].eq_ignore_ascii_case(b"CLASS") { if name.eq_ignore_ascii_case("NONE") { return Some(NONE); }
if let Ok(c) = name[5..].parse::<u16>() {
return Some(Class(c))
}
}
None None
} }
pub fn write_class_name(self, f: &mut fmt::Formatter) -> fmt::Result { /// parses known names (mnemonics)
if self.is_qclass() { pub fn from_known_name(name: &str) -> Option<Self> {
self.write_generic_name(f) use std::ascii::AsciiExt;
Self::from_known_name_without_any(name).or_else(|| {
if name.eq_ignore_ascii_case("ANY") { return Some(ANY); }
None
})
}
/// parses generic names of the form "CLASS..."
pub fn from_generic_name(name: &str) -> Option<Self> {
use std::ascii::AsciiExt;
if name.as_bytes()[0..5].eq_ignore_ascii_case(b"CLASS") {
name[5..].parse::<u16>().ok().map(Class)
} else { } else {
write!(f, "{}", self) None
} }
} }
pub fn write_generic_name(self, f: &mut fmt::Formatter) -> fmt::Result { /// parses any name (mnemonics and "CLASS..."), but not `ANY`
write!(f, "CLASS{}", self.0) /// ("CLASS255" works though)
pub fn from_name_without_any(name: &str) -> Option<Self> {
Self::from_generic_name(name).or_else(|| {
Self::from_known_name_without_any(name)
})
} }
pub fn generic_name(self) -> String { /// parses any name (mnemonics and "CLASS...")
format!("CLASS{}", self.0) pub fn from_name(name: &str) -> Option<Self> {
Self::from_generic_name(name).or_else(|| {
Self::from_known_name(name)
})
} }
} }
@ -125,17 +190,10 @@ impl From<KnownQClass> for Class {
impl fmt::Display for Class { impl fmt::Display for Class {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let n = match *self { match self.known_name() {
IN => "IN", Some(n) => write!(f, "{}", n),
CH => "CH", None => self.write_generic_name(f),
HS => "HS", }
NONE => "NONE",
ANY => "ANY",
_ => {
return self.write_generic_name(f)
},
};
write!(f, "{}", n)
} }
} }
@ -148,7 +206,7 @@ impl DnsPacketData for Class {
impl DnsTextData for Class { impl DnsTextData for Class {
fn dns_parse(data: &mut &str) -> Result<Self> { fn dns_parse(data: &mut &str) -> Result<Self> {
let field = next_field(data)?; let field = next_field(data)?;
Class::from_name(field).ok_or_else(|| format_err!("unknown class {:?}", field)) Class::from_name(field).ok_or_else(|| format_err!("unknown CLASS {:?}", field))
} }
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {

View File

@ -5,13 +5,9 @@ use ser::text::{DnsTextData, DnsTextFormatter, next_field};
use std::fmt; use std::fmt;
use std::io::Cursor; use std::io::Cursor;
/// A single quoted non-empty URL. /// timestamp in seconds since epoch (ignoring leap seconds)
/// ///
/// Actually shouldn't allow escapes (i.e. no backslash in the content); /// Is expected to wrap around.
/// but to make sure we can export and import any data we allow standard
/// escape mechanisms and even accept unquoted input.
///
/// No whitespace allowed, last field.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct Time(u32); pub struct Time(u32);

View File

@ -1,3 +1,5 @@
//! Types and constants for DNS TYPes
use bytes::Bytes; use bytes::Bytes;
use errors::*; use errors::*;
use records::registry::{lookup_type_to_name, lookup_type_name}; use records::registry::{lookup_type_to_name, lookup_type_name};
@ -7,305 +9,504 @@ use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::io::Cursor; use std::io::Cursor;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] /// a host address
pub struct Type(pub u16);
pub const A : Type = Type(KnownType::A as u16); pub const A : Type = Type(KnownType::A as u16);
/// an authoritative name server
pub const NS : Type = Type(KnownType::NS as u16); pub const NS : Type = Type(KnownType::NS as u16);
/// a mail destination (OBSOLETE - use MX)
pub const MD : Type = Type(KnownType::MD as u16); pub const MD : Type = Type(KnownType::MD as u16);
/// a mail forwarder (OBSOLETE - use MX)
pub const MF : Type = Type(KnownType::MF as u16); pub const MF : Type = Type(KnownType::MF as u16);
/// the canonical name for an alias
pub const CNAME : Type = Type(KnownType::CNAME as u16); pub const CNAME : Type = Type(KnownType::CNAME as u16);
/// marks the start of a zone of authority
pub const SOA : Type = Type(KnownType::SOA as u16); pub const SOA : Type = Type(KnownType::SOA as u16);
/// a mailbox domain name (EXPERIMENTAL)
pub const MB : Type = Type(KnownType::MB as u16); pub const MB : Type = Type(KnownType::MB as u16);
/// a mail group member (EXPERIMENTAL)
pub const MG : Type = Type(KnownType::MG as u16); pub const MG : Type = Type(KnownType::MG as u16);
/// a mail rename domain name (EXPERIMENTAL)
pub const MR : Type = Type(KnownType::MR as u16); pub const MR : Type = Type(KnownType::MR as u16);
/// a null RR (EXPERIMENTAL)
pub const NULL : Type = Type(KnownType::NULL as u16); pub const NULL : Type = Type(KnownType::NULL as u16);
/// a well known service description
pub const WKS : Type = Type(KnownType::WKS as u16); pub const WKS : Type = Type(KnownType::WKS as u16);
/// a domain name pointer
pub const PTR : Type = Type(KnownType::PTR as u16); pub const PTR : Type = Type(KnownType::PTR as u16);
/// host information
pub const HINFO : Type = Type(KnownType::HINFO as u16); pub const HINFO : Type = Type(KnownType::HINFO as u16);
/// mailbox or mail list information
pub const MINFO : Type = Type(KnownType::MINFO as u16); pub const MINFO : Type = Type(KnownType::MINFO as u16);
/// mail exchange
pub const MX : Type = Type(KnownType::MX as u16); pub const MX : Type = Type(KnownType::MX as u16);
/// text strings
pub const TXT : Type = Type(KnownType::TXT as u16); pub const TXT : Type = Type(KnownType::TXT as u16);
/// for Responsible Person
pub const RP : Type = Type(KnownType::RP as u16); pub const RP : Type = Type(KnownType::RP as u16);
/// for AFS Data Base location
pub const AFSDB : Type = Type(KnownType::AFSDB as u16); pub const AFSDB : Type = Type(KnownType::AFSDB as u16);
/// for X.25 PSDN address
pub const X25 : Type = Type(KnownType::X25 as u16); pub const X25 : Type = Type(KnownType::X25 as u16);
/// for ISDN address
pub const ISDN : Type = Type(KnownType::ISDN as u16); pub const ISDN : Type = Type(KnownType::ISDN as u16);
/// for Route Through
pub const RT : Type = Type(KnownType::RT as u16); pub const RT : Type = Type(KnownType::RT as u16);
/// for NSAP address, NSAP style A record
pub const NSAP : Type = Type(KnownType::NSAP as u16); pub const NSAP : Type = Type(KnownType::NSAP as u16);
/// for domain name pointer, NSAP style
pub const NSAP_PTR : Type = Type(KnownType::NSAP_PTR as u16); pub const NSAP_PTR : Type = Type(KnownType::NSAP_PTR as u16);
/// for security signature
pub const SIG : Type = Type(KnownType::SIG as u16); pub const SIG : Type = Type(KnownType::SIG as u16);
/// for security key
pub const KEY : Type = Type(KnownType::KEY as u16); pub const KEY : Type = Type(KnownType::KEY as u16);
/// X.400 mail mapping information
pub const PX : Type = Type(KnownType::PX as u16); pub const PX : Type = Type(KnownType::PX as u16);
/// Geographical Position
pub const GPOS : Type = Type(KnownType::GPOS as u16); pub const GPOS : Type = Type(KnownType::GPOS as u16);
/// IP6 Address
pub const AAAA : Type = Type(KnownType::AAAA as u16); pub const AAAA : Type = Type(KnownType::AAAA as u16);
/// Location Information
pub const LOC : Type = Type(KnownType::LOC as u16); pub const LOC : Type = Type(KnownType::LOC as u16);
/// Next Domain (OBSOLETE)
pub const NXT : Type = Type(KnownType::NXT as u16); pub const NXT : Type = Type(KnownType::NXT as u16);
/// Endpoint Identifier
pub const EID : Type = Type(KnownType::EID as u16); pub const EID : Type = Type(KnownType::EID as u16);
/// Nimrod Locator
pub const NIMLOC : Type = Type(KnownType::NIMLOC as u16); pub const NIMLOC : Type = Type(KnownType::NIMLOC as u16);
/// Server Selection
pub const SRV : Type = Type(KnownType::SRV as u16); pub const SRV : Type = Type(KnownType::SRV as u16);
/// ATM Address
pub const ATMA : Type = Type(KnownType::ATMA as u16); pub const ATMA : Type = Type(KnownType::ATMA as u16);
/// Naming Authority Pointer
pub const NAPTR : Type = Type(KnownType::NAPTR as u16); pub const NAPTR : Type = Type(KnownType::NAPTR as u16);
/// Key Exchanger
pub const KX : Type = Type(KnownType::KX as u16); pub const KX : Type = Type(KnownType::KX as u16);
/// CERT
pub const CERT : Type = Type(KnownType::CERT as u16); pub const CERT : Type = Type(KnownType::CERT as u16);
/// A6 (OBSOLETE - use AAAA)
pub const A6 : Type = Type(KnownType::A6 as u16); pub const A6 : Type = Type(KnownType::A6 as u16);
/// DNAME
pub const DNAME : Type = Type(KnownType::DNAME as u16); pub const DNAME : Type = Type(KnownType::DNAME as u16);
/// SINK
pub const SINK : Type = Type(KnownType::SINK as u16); pub const SINK : Type = Type(KnownType::SINK as u16);
/// OPT
pub const OPT : Type = Type(KnownMetaType::OPT as u16); pub const OPT : Type = Type(KnownMetaType::OPT as u16);
/// APL
pub const APL : Type = Type(KnownType::APL as u16); pub const APL : Type = Type(KnownType::APL as u16);
/// Delegation Signer
pub const DS : Type = Type(KnownType::DS as u16); pub const DS : Type = Type(KnownType::DS as u16);
/// SSH Key Fingerprint
pub const SSHFP : Type = Type(KnownType::SSHFP as u16); pub const SSHFP : Type = Type(KnownType::SSHFP as u16);
/// IPSECKEY
pub const IPSECKEY : Type = Type(KnownType::IPSECKEY as u16); pub const IPSECKEY : Type = Type(KnownType::IPSECKEY as u16);
/// RRSIG
pub const RRSIG : Type = Type(KnownType::RRSIG as u16); pub const RRSIG : Type = Type(KnownType::RRSIG as u16);
/// NSEC
pub const NSEC : Type = Type(KnownType::NSEC as u16); pub const NSEC : Type = Type(KnownType::NSEC as u16);
/// DNSKEY
pub const DNSKEY : Type = Type(KnownType::DNSKEY as u16); pub const DNSKEY : Type = Type(KnownType::DNSKEY as u16);
/// DHCID
pub const DHCID : Type = Type(KnownType::DHCID as u16); pub const DHCID : Type = Type(KnownType::DHCID as u16);
/// NSEC3
pub const NSEC3 : Type = Type(KnownType::NSEC3 as u16); pub const NSEC3 : Type = Type(KnownType::NSEC3 as u16);
/// NSEC3PARAM
pub const NSEC3PARAM : Type = Type(KnownType::NSEC3PARAM as u16); pub const NSEC3PARAM : Type = Type(KnownType::NSEC3PARAM as u16);
/// TLSA
pub const TLSA : Type = Type(KnownType::TLSA as u16); pub const TLSA : Type = Type(KnownType::TLSA as u16);
/// S/MIME cert association
pub const SMIMEA : Type = Type(KnownType::SMIMEA as u16); pub const SMIMEA : Type = Type(KnownType::SMIMEA as u16);
/// Host Identity Protocol
pub const HIP : Type = Type(KnownType::HIP as u16); pub const HIP : Type = Type(KnownType::HIP as u16);
/// NINFO
pub const NINFO : Type = Type(KnownType::NINFO as u16); pub const NINFO : Type = Type(KnownType::NINFO as u16);
/// RKEY
pub const RKEY : Type = Type(KnownType::RKEY as u16); pub const RKEY : Type = Type(KnownType::RKEY as u16);
/// Trust Anchor LINK
pub const TALINK : Type = Type(KnownType::TALINK as u16); pub const TALINK : Type = Type(KnownType::TALINK as u16);
/// Child DS
pub const CDS : Type = Type(KnownType::CDS as u16); pub const CDS : Type = Type(KnownType::CDS as u16);
/// DNSKEY(s) the Child wants reflected in DS
pub const CDNSKEY : Type = Type(KnownType::CDNSKEY as u16); pub const CDNSKEY : Type = Type(KnownType::CDNSKEY as u16);
/// OpenPGP Key
pub const OPENPGPKEY : Type = Type(KnownType::OPENPGPKEY as u16); pub const OPENPGPKEY : Type = Type(KnownType::OPENPGPKEY as u16);
/// Child-To-Parent Synchronization
pub const CSYNC : Type = Type(KnownType::CSYNC as u16); pub const CSYNC : Type = Type(KnownType::CSYNC as u16);
/// SPF
pub const SPF : Type = Type(KnownType::SPF as u16); pub const SPF : Type = Type(KnownType::SPF as u16);
/// UINFO
pub const UINFO : Type = Type(KnownType::UINFO as u16); pub const UINFO : Type = Type(KnownType::UINFO as u16);
/// UID
pub const UID : Type = Type(KnownType::UID as u16); pub const UID : Type = Type(KnownType::UID as u16);
/// GID
pub const GID : Type = Type(KnownType::GID as u16); pub const GID : Type = Type(KnownType::GID as u16);
/// UNSPEC
pub const UNSPEC : Type = Type(KnownType::UNSPEC as u16); pub const UNSPEC : Type = Type(KnownType::UNSPEC as u16);
/// NID
pub const NID : Type = Type(KnownType::NID as u16); pub const NID : Type = Type(KnownType::NID as u16);
/// L32
pub const L32 : Type = Type(KnownType::L32 as u16); pub const L32 : Type = Type(KnownType::L32 as u16);
/// L64
pub const L64 : Type = Type(KnownType::L64 as u16); pub const L64 : Type = Type(KnownType::L64 as u16);
/// LP
pub const LP : Type = Type(KnownType::LP as u16); pub const LP : Type = Type(KnownType::LP as u16);
/// an EUI-48 address
pub const EUI48 : Type = Type(KnownType::EUI48 as u16); pub const EUI48 : Type = Type(KnownType::EUI48 as u16);
/// an EUI-64 address
pub const EUI64 : Type = Type(KnownType::EUI64 as u16); pub const EUI64 : Type = Type(KnownType::EUI64 as u16);
/// Transaction Key
pub const TKEY : Type = Type(KnownMetaType::TKEY as u16); pub const TKEY : Type = Type(KnownMetaType::TKEY as u16);
/// Transaction Signature
pub const TSIG : Type = Type(KnownMetaType::TSIG as u16); pub const TSIG : Type = Type(KnownMetaType::TSIG as u16);
/// incremental transfer
pub const IXFR : Type = Type(KnownQType::IXFR as u16); pub const IXFR : Type = Type(KnownQType::IXFR as u16);
/// transfer of an entire zone
pub const AXFR : Type = Type(KnownQType::AXFR as u16); pub const AXFR : Type = Type(KnownQType::AXFR as u16);
/// mailbox-related RRs (MB, MG or MR)
pub const MAILB : Type = Type(KnownQType::MAILB as u16); pub const MAILB : Type = Type(KnownQType::MAILB as u16);
/// mail agent RRs (OBSOLETE - see MX)
pub const MAILA : Type = Type(KnownQType::MAILA as u16); pub const MAILA : Type = Type(KnownQType::MAILA as u16);
/// "*", a request for all records the server/cache has available
pub const ANY : Type = Type(KnownQType::ANY as u16); pub const ANY : Type = Type(KnownQType::ANY as u16);
/// URI
pub const URI : Type = Type(KnownType::URI as u16); pub const URI : Type = Type(KnownType::URI as u16);
/// Certification Authority Restriction
pub const CAA : Type = Type(KnownType::CAA as u16); pub const CAA : Type = Type(KnownType::CAA as u16);
/// Application Visibility and Control
pub const AVC : Type = Type(KnownType::AVC as u16); pub const AVC : Type = Type(KnownType::AVC as u16);
/// Digital Object Architecture
pub const DOA : Type = Type(KnownType::DOA as u16); pub const DOA : Type = Type(KnownType::DOA as u16);
/// DNSSEC Trust Authorities
pub const TA : Type = Type(KnownType::TA as u16); pub const TA : Type = Type(KnownType::TA as u16);
/// DNSSEC Lookaside Validation
pub const DLV : Type = Type(KnownType::DLV as u16); pub const DLV : Type = Type(KnownType::DLV as u16);
/// powerdns feature: authoritate should resolve to A and AAAA
pub const ALIAS : Type = Type(KnownType::ALIAS as u16); pub const ALIAS : Type = Type(KnownType::ALIAS as u16);
/// known data TYPEs
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u16)] #[repr(u16)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum KnownType { pub enum KnownType {
// try to list "original" rfc // try to list "original" rfc
/// a host address
A = 0x0001, // RFC 1035 A = 0x0001, // RFC 1035
/// an authoritative name server
NS = 0x0002, // RFC 1035 NS = 0x0002, // RFC 1035
/// a mail destination (OBSOLETE - use MX)
MD = 0x0003, // RFC 1035 MD = 0x0003, // RFC 1035
/// a mail forwarder (OBSOLETE - use MX)
MF = 0x0004, // RFC 1035 MF = 0x0004, // RFC 1035
/// the canonical name for an alias
CNAME = 0x0005, // RFC 1035 CNAME = 0x0005, // RFC 1035
/// marks the start of a zone of authority
SOA = 0x0006, // RFC 1035 SOA = 0x0006, // RFC 1035
/// a mailbox domain name (EXPERIMENTAL)
MB = 0x0007, // RFC 1035 MB = 0x0007, // RFC 1035
/// a mail group member (EXPERIMENTAL)
MG = 0x0008, // RFC 1035 MG = 0x0008, // RFC 1035
/// a mail rename domain name (EXPERIMENTAL)
MR = 0x0009, // RFC 1035 MR = 0x0009, // RFC 1035
/// a null RR (EXPERIMENTAL)
NULL = 0x000a, // RFC 1035 NULL = 0x000a, // RFC 1035
/// a well known service description
WKS = 0x000b, // RFC 1035 WKS = 0x000b, // RFC 1035
/// a domain name pointer
PTR = 0x000c, // RFC 1035 PTR = 0x000c, // RFC 1035
/// host information
HINFO = 0x000d, // RFC 1035 HINFO = 0x000d, // RFC 1035
/// mailbox or mail list information
MINFO = 0x000e, // RFC 1035 MINFO = 0x000e, // RFC 1035
/// mail exchange
MX = 0x000f, // RFC 1035 MX = 0x000f, // RFC 1035
/// text strings
TXT = 0x0010, // RFC 1035 TXT = 0x0010, // RFC 1035
/// for Responsible Person
RP = 0x0011, // RFC 1183 RP = 0x0011, // RFC 1183
/// for AFS Data Base location
AFSDB = 0x0012, // RFC 1183 AFSDB = 0x0012, // RFC 1183
/// for X.25 PSDN address
X25 = 0x0013, // RFC 1183 X25 = 0x0013, // RFC 1183
/// for ISDN address
ISDN = 0x0014, // RFC 1183 ISDN = 0x0014, // RFC 1183
/// for Route Through
RT = 0x0015, // RFC 1183 RT = 0x0015, // RFC 1183
/// for NSAP address, NSAP style A record
NSAP = 0x0016, // RFC 1706 NSAP = 0x0016, // RFC 1706
/// for domain name pointer, NSAP style
NSAP_PTR = 0x0017, // RFC 1348 NSAP_PTR = 0x0017, // RFC 1348
/// for security signature
SIG = 0x0018, // RFC 2535 SIG = 0x0018, // RFC 2535
/// for security key
KEY = 0x0019, // RFC 2535 KEY = 0x0019, // RFC 2535
/// X.400 mail mapping information
PX = 0x001a, // RFC 2163 PX = 0x001a, // RFC 2163
/// Geographical Position
GPOS = 0x001b, // RFC 1712 GPOS = 0x001b, // RFC 1712
/// IP6 Address
AAAA = 0x001c, // RFC 3596 AAAA = 0x001c, // RFC 3596
/// Location Information
LOC = 0x001d, // RFC 1876 LOC = 0x001d, // RFC 1876
/// Next Domain (OBSOLETE)
NXT = 0x001e, // RFC 2535 NXT = 0x001e, // RFC 2535
/// Endpoint Identifier
EID = 0x001f, // Michael Patton: http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt EID = 0x001f, // Michael Patton: http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
/// Nimrod Locator
NIMLOC = 0x0020, // Michael Patton: http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt NIMLOC = 0x0020, // Michael Patton: http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt
/// Server Selection
SRV = 0x0021, // RFC 2782 SRV = 0x0021, // RFC 2782
/// ATM Address
ATMA = 0x0022, // http://www.broadband-forum.org/ftp/pub/approved-specs/af-dans-0152.000.pdf ATMA = 0x0022, // http://www.broadband-forum.org/ftp/pub/approved-specs/af-dans-0152.000.pdf
/// Naming Authority Pointer
NAPTR = 0x0023, // RFC 2168 NAPTR = 0x0023, // RFC 2168
/// Key Exchanger
KX = 0x0024, // RFC 2230 KX = 0x0024, // RFC 2230
/// CERT
CERT = 0x0025, // RFC 4398 CERT = 0x0025, // RFC 4398
/// A6 (OBSOLETE - use AAAA)
A6 = 0x0026, // RFC 2874 A6 = 0x0026, // RFC 2874
/// DNAME
DNAME = 0x0027, // RFC 6672 DNAME = 0x0027, // RFC 6672
/// SINK
SINK = 0x0028, // Donald E Eastlake: http://tools.ietf.org/html/draft-eastlake-kitchen-sink SINK = 0x0028, // Donald E Eastlake: http://tools.ietf.org/html/draft-eastlake-kitchen-sink
// OPT (0x0029) is a meta type // OPT (0x0029) is a meta type
/// APL
APL = 0x002a, // RFC 3123 APL = 0x002a, // RFC 3123
/// Delegation Signer
DS = 0x002b, // RFC 3658 DS = 0x002b, // RFC 3658
/// SSH Key Fingerprint
SSHFP = 0x002c, // RFC 4255 SSHFP = 0x002c, // RFC 4255
/// IPSECKEY
IPSECKEY = 0x002d, // RFC 4025 IPSECKEY = 0x002d, // RFC 4025
/// RRSIG
RRSIG = 0x002e, // RFC 4034 RRSIG = 0x002e, // RFC 4034
/// NSEC
NSEC = 0x002f, // RFC 4034 NSEC = 0x002f, // RFC 4034
/// DNSKEY
DNSKEY = 0x0030, // RFC 4034 DNSKEY = 0x0030, // RFC 4034
/// DHCID
DHCID = 0x0031, // RFC 4701 DHCID = 0x0031, // RFC 4701
/// NSEC3
NSEC3 = 0x0032, // RFC 5155 NSEC3 = 0x0032, // RFC 5155
/// NSEC3PARAM
NSEC3PARAM = 0x0033, // RFC 5155 NSEC3PARAM = 0x0033, // RFC 5155
/// TLSA
TLSA = 0x0034, // RFC 6698 TLSA = 0x0034, // RFC 6698
/// S/MIME cert association
SMIMEA = 0x0035, // RFC 8162 SMIMEA = 0x0035, // RFC 8162
/// Host Identity Protocol
HIP = 0x0037, // RFC 8005 HIP = 0x0037, // RFC 8005
/// NINFO
NINFO = 0x0038, // Jim Reid NINFO = 0x0038, // Jim Reid
/// RKEY
RKEY = 0x0039, // Jim Reid RKEY = 0x0039, // Jim Reid
/// Trust Anchor LINK
TALINK = 0x003a, // Wouter Wijngaards TALINK = 0x003a, // Wouter Wijngaards
/// Child DS
CDS = 0x003b, // RFC 7344 CDS = 0x003b, // RFC 7344
/// DNSKEY(s) the Child wants reflected in DS
CDNSKEY = 0x003c, // RFC 7344 CDNSKEY = 0x003c, // RFC 7344
/// OpenPGP Key
OPENPGPKEY = 0x003d, // RFC 7929 OPENPGPKEY = 0x003d, // RFC 7929
/// Child-To-Parent Synchronization
CSYNC = 0x003e, // RFC 7477 CSYNC = 0x003e, // RFC 7477
/// SPF
SPF = 0x0063, // RFC 7208 SPF = 0x0063, // RFC 7208
/// UINFO
UINFO = 0x0064, // IANA-Reserved UINFO = 0x0064, // IANA-Reserved
/// UID
UID = 0x0065, // IANA-Reserved UID = 0x0065, // IANA-Reserved
/// GID
GID = 0x0066, // IANA-Reserved GID = 0x0066, // IANA-Reserved
/// UNSPEC
UNSPEC = 0x0067, // IANA-Reserved UNSPEC = 0x0067, // IANA-Reserved
/// NID
NID = 0x0068, // RFC 6742 NID = 0x0068, // RFC 6742
/// L32
L32 = 0x0069, // RFC 6742 L32 = 0x0069, // RFC 6742
/// L64
L64 = 0x006a, // RFC 6742 L64 = 0x006a, // RFC 6742
/// LP
LP = 0x006b, // RFC 6742 LP = 0x006b, // RFC 6742
/// an EUI-48 address
EUI48 = 0x006c, // RFC 7043 EUI48 = 0x006c, // RFC 7043
/// an EUI-64 address
EUI64 = 0x006d, // RFC 7043 EUI64 = 0x006d, // RFC 7043
// 0x0080..0x00ff: meta and qtypes // 0x0080..0x00ff: meta and qtypes
/// URI
URI = 0x0100, // RFC 7553 URI = 0x0100, // RFC 7553
/// Certification Authority Restriction
CAA = 0x0101, // RFC 6844 CAA = 0x0101, // RFC 6844
/// Application Visibility and Control
AVC = 0x0102, // Wolfgang Riedel AVC = 0x0102, // Wolfgang Riedel
/// Digital Object Architecture
DOA = 0x0103, // http://www.iana.org/go/draft-durand-doa-over-dns DOA = 0x0103, // http://www.iana.org/go/draft-durand-doa-over-dns
/// DNSSEC Trust Authorities
TA = 0x8000, // TA = 0x8000, //
/// DNSSEC Lookaside Validation
DLV = 0x8001, // RFC 4431 DLV = 0x8001, // RFC 4431
/// powerdns feature: authoritate should resolve to A and AAAA
ALIAS = 0xff79, // powerdns ALIAS = 0xff79, // powerdns
} }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] /// known QTYPEs
#[repr(u16)]
#[allow(non_camel_case_types)]
pub enum KnownMetaType {
OPT = 0x0029, // RFC 6891
TKEY = 0x00f9, // RFC 2930
TSIG = 0x00fa, // RFC 2845
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u16)] #[repr(u16)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum KnownQType { pub enum KnownQType {
/// incremental transfer
IXFR = 0x00fb, // RFC 1995 IXFR = 0x00fb, // RFC 1995
/// transfer of an entire zone
AXFR = 0x00fc, // RFC 1035 AXFR = 0x00fc, // RFC 1035
/// mailbox-related RRs (MB, MG or MR)
MAILB = 0x00fd, // RFC 1035 MAILB = 0x00fd, // RFC 1035
/// mail agent RRs (OBSOLETE - see MX)
MAILA = 0x00fe, // RFC 1035 MAILA = 0x00fe, // RFC 1035
ANY = 0x00ff, // RFC 1035, "*" /// "*", a request for all records the server/cache has available
ANY = 0x00ff, // RFC 1035
} }
impl Type { /// known Meta-TYPEs
pub fn name(self) -> Cow<'static, str> { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
if let Some(name) = lookup_type_to_name(self) { #[repr(u16)]
Cow::Borrowed(name) #[allow(non_camel_case_types)]
} else { pub enum KnownMetaType {
Cow::Owned(self.generic_name()) /// OPT
} OPT = 0x0029, // RFC 6891
} /// Transaction Key
TKEY = 0x00f9, // RFC 2930
/// Transaction Signature
TSIG = 0x00fa, // RFC 2845
}
// 0x0080-0x00FF is reserved for QTYPEs and Meta TYPEs. /// DNS (RR)TYPE
// OPT is a special meta type ///
/// Originally QTYPE was a superset of TYPE; RFC 6895 now defines:
///
/// > There are three subcategories of RRTYPE numbers: data TYPEs,
/// > QTYPEs, and Meta-TYPEs.
///
/// ## `ANY`
///
/// QTYPE 255 ("*") doesn't seem to have an official mnemonic; `ANY` is
/// used in most tools though.
///
/// The `ANY` mnemonic conflicts with the QCLASS `ANY` though; the name
/// functions for `Class` have `_without_any` variants though.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Type(pub u16);
impl Type {
/// whether TYPE is known or reserved to be a QTYPE or a Meta-TYPE.
///
/// 0x0080-0x00FF is reserved for QTYPEs and Meta-TYPEs; OPT is a
/// special Meta-TYPE.
pub fn is_q_or_meta_type(self) -> bool { pub fn is_q_or_meta_type(self) -> bool {
self == OPT || (self.0 >= 128 && self.0 < 256) self == OPT || (self.0 >= 128 && self.0 < 256)
} }
// checks for known qtypes /// map to `KnownQType`
pub fn known_qtype(self) -> Option<KnownQType> {
Some(match self {
IXFR => KnownQType::IXFR,
AXFR => KnownQType::AXFR,
MAILB => KnownQType::MAILB,
MAILA => KnownQType::MAILA,
ANY => KnownQType::ANY,
_ => return None,
})
}
/// whether TYPE is known to be a QTYPE
pub fn is_known_qtype(self) -> bool { pub fn is_known_qtype(self) -> bool {
match self { self.known_qtype().is_some()
IXFR => true,
AXFR => true,
MAILB => true,
MAILA => true,
ANY => true,
_ => false,
}
} }
// checks for known meta types /// map to `KnownMetaType`
pub fn known_meta_type(self) -> Option<KnownMetaType> {
Some(match self {
OPT => KnownMetaType::OPT,
TKEY => KnownMetaType::TKEY,
TSIG => KnownMetaType::TSIG,
_ => return None,
})
}
/// whether TYPE is known to be a Meta-TYPE
pub fn is_known_meta_type(self) -> bool { pub fn is_known_meta_type(self) -> bool {
match self { self.known_meta_type().is_some()
OPT => true, }
TKEY => true,
TSIG => true, /// name for TYPE if known
_ => false, ///
} /// Known TYPEs are represented using their known mnemonic, others
} /// return None.
pub fn known_name(self) -> Option<&'static str> {
/// uses generic name for QTYPEs/Meta TYPEs (`is_q_or_meta_type`) lookup_type_to_name(self)
pub fn type_name(self) -> Cow<'static, str> { }
if self.is_q_or_meta_type() {
Cow::Owned(self.generic_name()) /// name for TYPE
} else { ///
self.name() /// Known TYPEes are represented using their known mnemonic, others
/// using the "TYPE..." syntax (RFC 3597).
pub fn name(self) -> Cow<'static, str> {
match self.known_name() {
Some(name) => Cow::Borrowed(name),
None => Cow::Owned(self.generic_name())
} }
} }
/// generic name "TYPE..."
pub fn generic_name(self) -> String { pub fn generic_name(self) -> String {
format!("TYPE{}", self.0) let mut result = String::new();
self.write_generic_name(&mut result).unwrap();
result
} }
pub fn from_name(name: &str) -> Option<Self> { /// directly write generic name "TYPE..." to some target
pub fn write_generic_name<W: fmt::Write>(self, w: &mut W) -> fmt::Result {
write!(w, "TYPE{}", self.0)
}
/// parses known names (mnemonics)
pub fn from_known_name(name: &str) -> Option<Self> {
lookup_type_name(name)
}
/// parses generic names of the form "TYPE..."
pub fn from_generic_name(name: &str) -> Option<Self> {
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
if let Some(t) = lookup_type_name(name) { return Some(t); }
if name.as_bytes()[0..4].eq_ignore_ascii_case(b"TYPE") { if name.as_bytes()[0..4].eq_ignore_ascii_case(b"TYPE") {
if let Ok(t) = name[4..].parse::<u16>() { name[4..].parse::<u16>().ok().map(Type)
return Some(Type(t));
}
}
None
}
/// similar to `from_name`, but doesn't accept QTYPE/Meta TYPE names (it
/// always accepts "TYPE..." names though, even if they are known to
/// be QTYPE/Meta TYPE)
pub fn type_from_name(name: &str) -> Option<Self> {
use std::ascii::AsciiExt;
if let Some(t) = lookup_type_name(name) {
if t.is_q_or_meta_type() { return None; }
return Some(t);
}
if name.as_bytes()[0..4].eq_ignore_ascii_case(b"TYPE") {
if let Ok(t) = name[4..].parse::<u16>() {
return Some(Type(t));
}
}
None
}
pub fn write_type_name(self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_q_or_meta_type() {
self.write_generic_name(f)
} else { } else {
write!(f, "{}", self) None
} }
} }
pub fn write_generic_name(self, f: &mut fmt::Formatter) -> fmt::Result { /// parses any name (mnemonics and "TYPE...")
write!(f, "TYPE{}", self.0) pub fn from_name(name: &str) -> Option<Self> {
Self::from_generic_name(name).or_else(|| {
Self::from_known_name(name)
})
} }
/// defined in RFC 1035 /// whether TYPE is defined in RFC 1035
pub fn well_known(self) -> bool { pub fn is_well_known(self) -> bool {
// 0x0001 (A) ... 0x0010 (TXT) are defined in RFC 1035 // 0x0001 (A) ... 0x0010 (TXT) are defined in RFC 1035
self.0 >= 0x0001 && self.0 <= 0x0010 self.0 >= 0x0001 && self.0 <= 0x0010
} }
/// require converting to canonical form for DNSSEC (i.e. names /// require converting to canonical form for DNSSEC (i.e. names must
/// must be converted to (ASCII) lower case, no compression) /// be converted to (ASCII) lower case).
/// ///
/// See https://tools.ietf.org/html/rfc4034#section-6.2 (updates RFC 3597). /// For DNSSEC name compression is forbidden too; all compressable
/// Also updated by https://tools.ietf.org/html/rfc6840#section-5.1 /// TYPEs are included in the list anyway.
pub fn canonical(self) -> bool { ///
/// See [RFC 4034 section 6.2][1] (obsoletes RFC 3597). Also
/// updated by [RFC 6840 section 5.1][2].
///
/// [1]: https://tools.ietf.org/html/rfc4034#section-6.2
/// [2]: https://tools.ietf.org/html/rfc6840#section-5.1
pub fn use_canonical_names(self) -> bool {
match self { match self {
NS => true, NS => true,
MD => true, MD => true,
@ -347,24 +548,23 @@ impl From<KnownType> for Type {
} }
} }
impl From<KnownMetaType> for Type {
fn from(value: KnownMetaType) -> Self {
Type(value as u16)
}
}
impl From<KnownQType> for Type { impl From<KnownQType> for Type {
fn from(value: KnownQType) -> Self { fn from(value: KnownQType) -> Self {
Type(value as u16) Type(value as u16)
} }
} }
impl From<KnownMetaType> for Type {
fn from(value: KnownMetaType) -> Self {
Type(value as u16)
}
}
impl fmt::Display for Type { impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(name) = lookup_type_to_name(*self) { match self.known_name() {
write!(f, "{}", name) Some(name) => write!(f, "{}", name),
} else { None => self.write_generic_name(f),
self.write_generic_name(f)
} }
} }
} }
@ -378,7 +578,7 @@ impl DnsPacketData for Type {
impl DnsTextData for Type { impl DnsTextData for Type {
fn dns_parse(data: &mut &str) -> Result<Self> { fn dns_parse(data: &mut &str) -> Result<Self> {
let field = next_field(data)?; let field = next_field(data)?;
Type::from_name(field).ok_or_else(|| format_err!("unknown type {:?}", field)) Type::from_name(field).ok_or_else(|| format_err!("unknown TYPE {:?}", field))
} }
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
@ -386,7 +586,6 @@ impl DnsTextData for Type {
} }
} }
#[cfg(test)] #[cfg(test)]
macro_rules! check_type { macro_rules! check_type {
($t:ident, $dec:expr) => { ($t:ident, $dec:expr) => {
@ -409,6 +608,10 @@ macro_rules! check_type {
}; };
} }
// the IANA registry uses decimal numbers; make sure there were no typos
// when converting them to hex in the constants above.
//
// also checks the registry has the name-to-number mapping.
#[cfg(test)] #[cfg(test)]
#[test] #[test]
fn check_types() { fn check_types() {

View File

@ -16,12 +16,23 @@ where
Ok(result) Ok(result)
} }
fn rrdata_parse<T>(data: &str) -> ::errors::Result<T>
where
T: StaticRRData
{
let mut data = data;
let result = T::dns_parse_rr_data(3600, classes::IN, T::TYPE, &mut data)?;
let data = data.trim();
ensure!(data.is_empty(), "didn't parse complete rrdata text, remaining: {:?}", data);
Ok(result)
}
fn check<T>(txt: &str, data: &'static [u8]) -> ::errors::Result<()> fn check<T>(txt: &str, data: &'static [u8]) -> ::errors::Result<()>
where where
T: StaticRRData + fmt::Debug + PartialEq T: StaticRRData + fmt::Debug + PartialEq
{ {
let d1: T = rrdata_de(data).context("couldn't parse binary record")?; let d1: T = rrdata_de(data).context("couldn't parse binary record")?;
let d2: T = text::parse(txt).context("couldn't parse text record")?; let d2: T = rrdata_parse(txt).context("couldn't parse text record")?;
ensure!(d1 == d2, "decoded data not equal: {:?} != {:?}", d1, d2); ensure!(d1 == d2, "decoded data not equal: {:?} != {:?}", d1, d2);
Ok(()) Ok(())
} }
@ -31,9 +42,9 @@ where
T: StaticRRData + fmt::Debug + PartialEq T: StaticRRData + fmt::Debug + PartialEq
{ {
let d1: T = rrdata_de(data).context("couldn't parse binary record")?; let d1: T = rrdata_de(data).context("couldn't parse binary record")?;
let d2: T = text::parse(txt).context("couldn't parse text record")?; let d2: T = rrdata_parse(txt).context("couldn't parse text record")?;
ensure!(d1 == d2, "decoded data not equal: {:?} != {:?}", d1, d2); ensure!(d1 == d2, "decoded data not equal: {:?} != {:?}", d1, d2);
Ok(()) Ok(())
} }
@ -61,7 +72,7 @@ where
s.push('"'); s.push('"');
for _ in 0..256 { s.push('a'); } for _ in 0..256 { s.push('a'); }
s.push('"'); s.push('"');
text::parse::<T>(&s).unwrap_err(); rrdata_parse::<T>(&s).unwrap_err();
} }
} }

View File

@ -52,4 +52,8 @@ impl RRDataPacket for UnknownRecord {
fn deserialize_rr_data(_ttl: u32, _rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> { fn deserialize_rr_data(_ttl: u32, _rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> {
UnknownRecord::deserialize(rr_type, data) UnknownRecord::deserialize(rr_type, data)
} }
fn rr_type(&self) -> Type {
self.rr_type
}
} }

View File

@ -1,9 +1,9 @@
use bytes::Bytes; use bytes::Bytes;
use common_types::{Class, Type}; use common_types::{Class, Type, classes};
use common_types::classes;
use errors::*; use errors::*;
use ser::DnsPacketData; use ser::DnsPacketData;
use ser::text::{DnsTextData, DnsTextFormatter}; use ser::text::{DnsTextData, DnsTextFormatter};
use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::io::Cursor; use std::io::Cursor;
@ -12,19 +12,25 @@ pub trait RRDataPacket {
where where
Self: Sized, Self: Sized,
; ;
fn rr_type(&self) -> Type;
} }
impl<T: DnsPacketData + StaticRRData> RRDataPacket for T { impl<T: DnsPacketData + StaticRRData> RRDataPacket for T {
fn deserialize_rr_data(_ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> { fn deserialize_rr_data(_ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> {
ensure!(rr_type == T::TYPE, "type mismatch"); ensure!(rr_type == T::TYPE, "type mismatch");
if T::CLASS != classes::ANY { if T::CLASS != classes::ANY {
ensure!(rr_class == T::CLASS, "class mismatch"); ensure!(rr_class == T::CLASS, "class mismatch: got {}, need {}", rr_class, T::CLASS);
} }
T::deserialize(data) T::deserialize(data)
} }
fn rr_type(&self) -> Type {
T::TYPE
}
} }
pub trait RRDataText: Sized { pub trait RRDataText {
fn dns_parse_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut &str) -> Result<Self> fn dns_parse_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut &str) -> Result<Self>
where where
Self: Sized, Self: Sized,
@ -32,18 +38,53 @@ pub trait RRDataText: Sized {
// format might fail if there is no (known) text representation. // format might fail if there is no (known) text representation.
fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result; fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result;
}
/* fn rr_type_txt(&self) -> Cow<'static, str> {
impl<T: DnsTextData> RRDataText for T { unimplemented!()
fn deserialize_rr_data(_ttl: u32, _rr_class: Class, _rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> { }
T::deserialize(data)
// (type, rrdata)
fn text(&self) -> Result<(String, String)> {
use std::fmt::Write;
let mut buf = String::new();
match write!(&mut buf, "{}", DnsDisplayRR(self)) {
Ok(()) => {
return Ok((self.rr_type_txt().into(), buf))
},
Err(_) => (),
}
buf.clear();
unimplemented!()
} }
} }
*/
pub trait RRData: RRDataPacket + DnsTextData { impl<T: DnsTextData + StaticRRData> RRDataText for T {
fn rr_type(&self) -> Type; fn dns_parse_rr_data(_ttl: u32, rr_class: Class, rr_type: Type, data: &mut &str) -> Result<Self>
where
Self: Sized,
{
ensure!(rr_type == T::TYPE, "type mismatch");
if T::CLASS != classes::ANY {
ensure!(rr_class == T::CLASS, "class mismatch: got {}, need {}", rr_class, T::CLASS);
}
T::dns_parse(data)
}
fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result {
self.dns_format(f)
}
}
#[derive(Debug)]
pub struct DnsDisplayRR<'a, T: RRDataText + ?Sized + 'a>(pub &'a T);
impl<'a, T: RRDataText + ?Sized + 'a> fmt::Display for DnsDisplayRR<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.dns_format_rr_data(&mut DnsTextFormatter::new(f))
}
}
pub trait RRData: RRDataPacket + RRDataText {
} }
pub trait StaticRRData: RRData { pub trait StaticRRData: RRData {

View File

@ -53,13 +53,13 @@ pub fn escape(data: &[u8]) -> String {
/// Each call to write!() makes sure a space is emitted to separate it /// Each call to write!() makes sure a space is emitted to separate it
/// from previous fields. /// from previous fields.
pub struct DnsTextFormatter<'a> { pub struct DnsTextFormatter<'a, 'b: 'a> {
f: &'a mut fmt::Formatter<'a>, f: &'a mut fmt::Formatter<'b>,
need_space: bool, need_space: bool,
} }
impl<'a> DnsTextFormatter<'a> { impl<'a, 'b> DnsTextFormatter<'a, 'b> {
pub fn new(f: &'a mut fmt::Formatter<'a>) -> Self { pub fn new(f: &'a mut fmt::Formatter<'b>) -> Self {
DnsTextFormatter { DnsTextFormatter {
f: f, f: f,
need_space: false, need_space: false,
@ -82,7 +82,7 @@ impl<'a> DnsTextFormatter<'a> {
/// direct access to underlying output; you'll need to call /// direct access to underlying output; you'll need to call
/// `next_field` and `end_field` manually. /// `next_field` and `end_field` manually.
pub fn inner(&mut self) -> &mut fmt::Formatter<'a> { pub fn inner(&mut self) -> &mut fmt::Formatter<'b> {
self.f self.f
} }
@ -113,3 +113,12 @@ where
ensure!(data.is_empty(), "didn't parse complete text, remaining: {:?}", data); ensure!(data.is_empty(), "didn't parse complete text, remaining: {:?}", data);
Ok(result) Ok(result)
} }
#[derive(Debug)]
pub struct DnsDisplay<'a, T: DnsTextData + ?Sized + 'a>(pub &'a T);
impl<'a, T: DnsTextData + ?Sized + 'a> fmt::Display for DnsDisplay<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.dns_format(&mut DnsTextFormatter::new(f))
}
}

View File

@ -73,9 +73,6 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
quote!{ quote!{
impl ::dnsbox_base::ser::RRData for #name { impl ::dnsbox_base::ser::RRData for #name {
fn rr_type(&self) -> ::dnsbox_base::common_types::Type {
::dnsbox_base::common_types::types::#name
}
} }
impl ::dnsbox_base::ser::StaticRRData for #name { impl ::dnsbox_base::ser::StaticRRData for #name {