This commit is contained in:
Stefan Bühler 2017-12-26 17:30:08 +01:00
parent 2e380af9bb
commit e0f597ba9c
13 changed files with 504 additions and 215 deletions

View File

@ -21,6 +21,7 @@ pub const ANY : Class = Class(KnownQClass::ANY as u16);
pub enum KnownClass { pub enum KnownClass {
// try to list "original" rfc // try to list "original" rfc
IN = 0x0001, // RFC 1035 IN = 0x0001, // RFC 1035
// CS = 0x0002, // "CSNET"
CH = 0x0003, // "Chaos" CH = 0x0003, // "Chaos"
HS = 0x0004, // "Hesiod" HS = 0x0004, // "Hesiod"
} }
@ -110,6 +111,18 @@ impl Class {
} }
} }
impl From<KnownClass> for Class {
fn from(value: KnownClass) -> Self {
Class(value as u16)
}
}
impl From<KnownQClass> for Class {
fn from(value: KnownQClass) -> Self {
Class(value as u16)
}
}
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 { let n = match *self {

View File

@ -5,14 +5,13 @@ pub mod classes;
pub mod types; pub mod types;
mod nsec; mod nsec;
mod nxt; mod nxt;
mod rr_type;
mod time; mod time;
mod uri; mod uri;
pub use self::binary::{HexShortBlob, Base64RemainingBlob, HexRemainingBlob}; pub use self::binary::{HexShortBlob, Base64RemainingBlob, HexRemainingBlob};
pub use self::name::{DnsName, DnsCanonicalName, DnsCompressedName}; pub use self::name::{DnsName, DnsCanonicalName, DnsCompressedName};
pub use self::nsec::{NsecTypeBitmap, NextHashedOwnerName}; pub use self::nsec::{NsecTypeBitmap, NextHashedOwnerName};
pub use self::rr_type::Type; pub use self::types::Type;
pub use self::classes::Class; pub use self::classes::Class;
pub use self::text::{ShortText, LongText, UnquotedShortText, RemainingText}; pub use self::text::{ShortText, LongText, UnquotedShortText, RemainingText};
pub use self::uri::UriText; pub use self::uri::UriText;

View File

@ -1,99 +0,0 @@
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<Bytes>) -> Result<Self> {
Ok(Type(DnsPacketData::deserialize(data)?))
}
}
impl DnsTextData for Type {
fn dns_parse(data: &mut &str) -> Result<Self> {
let field = next_field(data)?;
if field.starts_with("TYPE") || field.starts_with("type") {
if let Ok(t) = field[4..].parse::<u16>() {
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)
}
}

View File

@ -1,4 +1,14 @@
use common_types::Type; use bytes::Bytes;
use errors::*;
use records::registry::{lookup_type_to_name, lookup_type_name};
use ser::DnsPacketData;
use ser::text::{DnsTextData, DnsTextFormatter, next_field};
use std::borrow::Cow;
use std::fmt;
use std::io::Cursor;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Type(pub u16);
pub const A : Type = Type(KnownType::A as u16); pub const A : Type = Type(KnownType::A as u16);
pub const NS : Type = Type(KnownType::NS as u16); pub const NS : Type = Type(KnownType::NS as u16);
@ -40,7 +50,7 @@ pub const CERT : Type = Type(KnownType::CERT as u16);
pub const A6 : Type = Type(KnownType::A6 as u16); pub const A6 : Type = Type(KnownType::A6 as u16);
pub const DNAME : Type = Type(KnownType::DNAME as u16); pub const DNAME : Type = Type(KnownType::DNAME as u16);
pub const SINK : Type = Type(KnownType::SINK as u16); pub const SINK : Type = Type(KnownType::SINK as u16);
pub const OPT : Type = Type(KnownType::OPT as u16); pub const OPT : Type = Type(KnownMetaType::OPT as u16);
pub const APL : Type = Type(KnownType::APL as u16); pub const APL : Type = Type(KnownType::APL as u16);
pub const DS : Type = Type(KnownType::DS as u16); pub const DS : Type = Type(KnownType::DS as u16);
pub const SSHFP : Type = Type(KnownType::SSHFP as u16); pub const SSHFP : Type = Type(KnownType::SSHFP as u16);
@ -72,19 +82,19 @@ pub const L64 : Type = Type(KnownType::L64 as u16);
pub const LP : Type = Type(KnownType::LP as u16); pub const LP : Type = Type(KnownType::LP as u16);
pub const EUI48 : Type = Type(KnownType::EUI48 as u16); pub const EUI48 : Type = Type(KnownType::EUI48 as u16);
pub const EUI64 : Type = Type(KnownType::EUI64 as u16); pub const EUI64 : Type = Type(KnownType::EUI64 as u16);
pub const TKEY : Type = Type(KnownType::TKEY as u16); pub const TKEY : Type = Type(KnownMetaType::TKEY as u16);
pub const TSIG : Type = Type(KnownType::TSIG as u16); pub const TSIG : Type = Type(KnownMetaType::TSIG as u16);
pub const IXFR : Type = Type(KnownType::IXFR as u16); pub const IXFR : Type = Type(KnownQType::IXFR as u16);
pub const AXFR : Type = Type(KnownType::AXFR as u16); pub const AXFR : Type = Type(KnownQType::AXFR as u16);
pub const MAILB : Type = Type(KnownType::MAILB as u16); pub const MAILB : Type = Type(KnownQType::MAILB as u16);
pub const MAILA : Type = Type(KnownType::MAILA as u16); pub const MAILA : Type = Type(KnownQType::MAILA as u16);
pub const ANY : Type = Type(KnownType::ANY as u16); pub const ANY : Type = Type(KnownQType::ANY as u16);
pub const URI : Type = Type(KnownType::URI as u16); pub const URI : Type = Type(KnownType::URI as u16);
pub const CAA : Type = Type(KnownType::CAA as u16); pub const CAA : Type = Type(KnownType::CAA as u16);
pub const AVC : Type = Type(KnownType::AVC as u16); pub const AVC : Type = Type(KnownType::AVC as u16);
pub const DOA : Type = Type(KnownType::DOA as u16); pub const DOA : Type = Type(KnownType::DOA as u16);
pub const TA : Type = Type(KnownType::TA as u16);
pub const DLV : Type = Type(KnownType::DLV as u16); pub const DLV : Type = Type(KnownType::DLV as u16);
pub const ADDR : Type = Type(KnownType::ADDR as u16);
pub const ALIAS : Type = Type(KnownType::ALIAS as u16); pub const ALIAS : Type = Type(KnownType::ALIAS as u16);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
@ -132,7 +142,7 @@ pub enum KnownType {
A6 = 0x0026, // RFC 2874 A6 = 0x0026, // RFC 2874
DNAME = 0x0027, // RFC 6672 DNAME = 0x0027, // RFC 6672
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, // RFC 6891 // OPT (0x0029) is a meta type
APL = 0x002a, // RFC 3123 APL = 0x002a, // RFC 3123
DS = 0x002b, // RFC 3658 DS = 0x002b, // RFC 3658
SSHFP = 0x002c, // RFC 4255 SSHFP = 0x002c, // RFC 4255
@ -164,22 +174,219 @@ pub enum KnownType {
LP = 0x006b, // RFC 6742 LP = 0x006b, // RFC 6742
EUI48 = 0x006c, // RFC 7043 EUI48 = 0x006c, // RFC 7043
EUI64 = 0x006d, // RFC 7043 EUI64 = 0x006d, // RFC 7043
// 0x0080..0x00ff: meta and qtypes
URI = 0x0100, // RFC 7553
CAA = 0x0101, // RFC 6844
AVC = 0x0102, // Wolfgang Riedel
DOA = 0x0103, // http://www.iana.org/go/draft-durand-doa-over-dns
TA = 0x8000, //
DLV = 0x8001, // RFC 4431
ALIAS = 0xff79, // powerdns
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u16)]
#[allow(non_camel_case_types)]
pub enum KnownMetaType {
OPT = 0x0029, // RFC 6891
TKEY = 0x00f9, // RFC 2930 TKEY = 0x00f9, // RFC 2930
TSIG = 0x00fa, // RFC 2845 TSIG = 0x00fa, // RFC 2845
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u16)]
#[allow(non_camel_case_types)]
pub enum KnownQType {
IXFR = 0x00fb, // RFC 1995 IXFR = 0x00fb, // RFC 1995
AXFR = 0x00fc, // RFC 1035 AXFR = 0x00fc, // RFC 1035
MAILB = 0x00fd, // RFC 1035 MAILB = 0x00fd, // RFC 1035
MAILA = 0x00fe, // RFC 1035 MAILA = 0x00fe, // RFC 1035
ANY = 0x00ff, // RFC 1035, "*" ANY = 0x00ff, // RFC 1035, "*"
URI = 0x0100, // RFC 7553
CAA = 0x0101, // RFC 6844
AVC = 0x0102, // Wolfgang Riedel
DOA = 0x0103, // http://www.iana.org/go/draft-durand-doa-over-dns
DLV = 0x8001, // RFC 4431
ADDR = 0xff78, // powerdns?
ALIAS = 0xff79, // powerdns?
} }
impl Type {
pub fn name(self) -> Cow<'static, str> {
if let Some(name) = lookup_type_to_name(self) {
Cow::Borrowed(name)
} else {
Cow::Owned(self.generic_name())
}
}
// 0x0080-0x00FF is reserved for QTYPEs and Meta TYPEs.
// OPT is a special meta type
pub fn is_q_or_meta_type(self) -> bool {
self == OPT || (self.0 >= 128 && self.0 < 256)
}
// checks for known qtypes
pub fn is_known_qtype(self) -> bool {
match self {
IXFR => true,
AXFR => true,
MAILB => true,
MAILA => true,
ANY => true,
_ => false,
}
}
// checks for known meta types
pub fn is_known_meta_type(self) -> bool {
match self {
OPT => true,
TKEY => true,
TSIG => true,
_ => false,
}
}
/// uses generic name for QTYPEs/Meta TYPEs (`is_q_or_meta_type`)
pub fn type_name(self) -> Cow<'static, str> {
if self.is_q_or_meta_type() {
Cow::Owned(self.generic_name())
} else {
self.name()
}
}
pub fn generic_name(self) -> String {
format!("TYPE{}", self.0)
}
pub fn from_name(name: &str) -> Option<Self> {
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 let Ok(t) = name[4..].parse::<u16>() {
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 {
write!(f, "{}", self)
}
}
pub fn write_generic_name(self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "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).
/// Also updated by https://tools.ietf.org/html/rfc6840#section-5.1
pub fn canonical(self) -> bool {
match self {
NS => true,
MD => true,
MF => true,
CNAME => true,
SOA => true,
MB => true,
MG => true,
MR => true,
PTR => true,
// HINFO => true, // removed by RFC 6840: doesn't have a name in data
MINFO => true,
MX => true,
// HINFO => true, // removed by RFC 6840: see above, also duplicate
RP => true,
AFSDB => true,
RT => true,
NSAP_PTR => true, // not listed in the RFCs, but probably should be.
SIG => true,
PX => true,
NXT => true,
SRV => true, // moved up to match numeric order
NAPTR => true,
KX => true,
// SRV => true, // moved up to match numeric order
A6 => true, // moved up to match numeric order
DNAME => true,
// A6 => true, // moved up to match numeric order
RRSIG => true,
// NSEC => true, // removed by RFC 6840
_ => false,
}
}
}
impl From<KnownType> for Type {
fn from(value: KnownType) -> Self {
Type(value as u16)
}
}
impl From<KnownMetaType> for Type {
fn from(value: KnownMetaType) -> Self {
Type(value as u16)
}
}
impl From<KnownQType> for Type {
fn from(value: KnownQType) -> Self {
Type(value as u16)
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(name) = lookup_type_to_name(*self) {
write!(f, "{}", name)
} else {
self.write_generic_name(f)
}
}
}
impl DnsPacketData for Type {
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
Ok(Type(DnsPacketData::deserialize(data)?))
}
}
impl DnsTextData for Type {
fn dns_parse(data: &mut &str) -> Result<Self> {
let field = next_field(data)?;
Type::from_name(field).ok_or_else(|| format_err!("unknown type {:?}", field))
}
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[cfg(test)] #[cfg(test)]
macro_rules! check_type { macro_rules! check_type {
($t:ident, $dec:expr) => { ($t:ident, $dec:expr) => {
@ -188,7 +395,7 @@ macro_rules! check_type {
// compare decimal value // compare decimal value
assert_eq!($t, Type($dec), "wrong decimal value for {}", stringify!($t)); assert_eq!($t, Type($dec), "wrong decimal value for {}", stringify!($t));
// make sure it's registered // make sure it's registered
assert_eq!(registry::name_to_type(stringify!($t)), Some($t), "{} not registered", stringify!($t)); assert_eq!(registry::lookup_type_name(stringify!($t)), Some($t), "{} not registered", stringify!($t));
} }
}; };
($t:ident, $dec:expr, $name:expr) => { ($t:ident, $dec:expr, $name:expr) => {
@ -197,7 +404,7 @@ macro_rules! check_type {
// compare decimal value // compare decimal value
assert_eq!($t, Type($dec), "wrong decimal value for {}", stringify!($t)); assert_eq!($t, Type($dec), "wrong decimal value for {}", stringify!($t));
// make sure it's registered // make sure it's registered
assert_eq!(registry::name_to_type($name), Some($t), "{} not registered as {:?}", stringify!($t), $name); assert_eq!(registry::lookup_type_name($name), Some($t), "{} not registered as {:?}", stringify!($t), $name);
} }
}; };
} }
@ -288,7 +495,7 @@ fn check_types() {
check_type!(CAA , 257); check_type!(CAA , 257);
check_type!(AVC , 258); check_type!(AVC , 258);
check_type!(DOA , 259); check_type!(DOA , 259);
check_type!(TA , 32768);
check_type!(DLV , 32769); check_type!(DLV , 32769);
check_type!(ADDR , 65400);
check_type!(ALIAS , 65401); check_type!(ALIAS , 65401);
} }

View File

@ -1,12 +1,18 @@
use std::collections::HashMap; use bytes::Bytes;
use std::any::TypeId;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::io::Cursor;
use std::marker::PhantomData; use std::marker::PhantomData;
use common_types::{Class, Type, types};
use errors::*;
use records::structs; use records::structs;
use common_types::types;
use common_types::Type;
use ser::{RRData, StaticRRData}; use ser::{RRData, StaticRRData};
// this should be enough for registered names
const TYPE_NAME_MAX_LEN: usize = 16;
lazy_static!{ lazy_static!{
static ref REGISTRY: Registry = Registry::init(); static ref REGISTRY: Registry = Registry::init();
} }
@ -15,31 +21,59 @@ fn registry() -> &'static Registry {
&*REGISTRY &*REGISTRY
} }
pub(crate) fn lookup_type_name(name: &str) -> Option<Type> {
if name.len() >= TYPE_NAME_MAX_LEN { return None; }
let mut name_buf_storage = [0u8; TYPE_NAME_MAX_LEN];
let name_buf = &mut name_buf_storage[..name.len()];
name_buf.copy_from_slice(name.as_bytes());
name_buf.make_ascii_uppercase();
let registry = registry();
let &t = registry.names_to_type.get(name_buf)?;
Some(t)
}
pub fn known_name_to_type(name: &str) -> Option<Type> { pub fn known_name_to_type(name: &str) -> Option<Type> {
let registry = registry(); let registry = registry();
let t = name_to_type(name)?; let t = lookup_type_name(name)?;
registry.type_parser.get(&t)?; registry.type_parser.get(&t)?;
Some(t) Some(t)
} }
pub fn name_to_type(name: &str) -> Option<Type> { pub(crate) fn lookup_type_to_name(rrtype: Type) -> Option<&'static str> {
let registry = registry();
let &t = registry.names_to_type.get(name)?;
Some(t)
}
pub(crate) fn type_name(rrtype: Type) -> Option<&'static str> {
let registry = registry(); let registry = registry();
registry.type_names.get(&rrtype).map(|s| s as _) registry.type_names.get(&rrtype).map(|s| s as _)
} }
#[doc(hidden)]
pub fn check_registration<T: StaticRRData + Sync + 'static>() {
registry().check_registration::<T>();
}
#[derive(Clone, Copy, Debug)]
struct TagRRDataType<T: RRData>(PhantomData<T>); struct TagRRDataType<T: RRData>(PhantomData<T>);
trait RRDataTypeParse: 'static {
fn type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
fn deserialize_rr_data(&self, ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Box<RRData>>;
}
impl<T: RRData + 'static> RRDataTypeParse for TagRRDataType<T> {
fn deserialize_rr_data(&self, ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Box<RRData>> {
T::deserialize_rr_data(ttl, rr_class, rr_type, data).map(|d| Box::new(d) as _)
}
}
struct Registry { struct Registry {
names_to_type: HashMap<String, Type>, // store (ascii) upper-case names.
names_to_type: HashMap<Vec<u8>, Type>,
type_names: HashMap<Type, String>, type_names: HashMap<Type, String>,
type_parser: HashMap<Type, ()>, type_parser: HashMap<Type, Box<RRDataTypeParse + Sync>>,
// make sure registrations are in order // make sure registrations are in order
prev_type: Option<Type>, prev_type: Option<Type>,
} }
@ -79,7 +113,7 @@ impl Registry {
r.register_known::<structs::SIG>(); r.register_known::<structs::SIG>();
r.register_known::<structs::KEY>(); r.register_known::<structs::KEY>();
r.register_known::<structs::PX>(); r.register_known::<structs::PX>();
r.register_unknown("GPOS" , types::GPOS); r.register_known::<structs::GPOS>();
r.register_known::<structs::AAAA>(); r.register_known::<structs::AAAA>();
r.register_known::<structs::LOC>(); r.register_known::<structs::LOC>();
r.register_known::<structs::NXT>(); r.register_known::<structs::NXT>();
@ -136,9 +170,12 @@ impl Registry {
r.register_known::<structs::CAA>(); r.register_known::<structs::CAA>();
r.register_unknown("AVC" , types::AVC); r.register_unknown("AVC" , types::AVC);
r.register_unknown("DOA" , types::DOA); r.register_unknown("DOA" , types::DOA);
r.register_unknown("TA" , types::TA);
r.register_unknown("DLV" , types::DLV); r.register_unknown("DLV" , types::DLV);
r.register_unknown("ADDR" , types::ADDR); r.register_known::<structs::ALIAS>();
r.register_unknown("ALIAS" , types::ALIAS);
// "ALL" could be an alias for the ANY type?
// assert!(r.names_to_type.insert("ALL".into(), types::ANY).is_none());
r r
} }
@ -148,7 +185,9 @@ impl Registry {
self.prev_type = Some(rrtype); self.prev_type = Some(rrtype);
let mut name: String = name.into(); let mut name: String = name.into();
name.make_ascii_uppercase(); name.make_ascii_uppercase();
assert!(self.names_to_type.insert(name.clone(), rrtype).is_none()); assert!(!name.starts_with("TYPE"), "must not register generic name: {}", name);
assert!(name.len() <= TYPE_NAME_MAX_LEN, "name too long: {} - maybe you need to increase TYPE_NAME_MAX_LEN", name);
assert!(self.names_to_type.insert(name.clone().into_bytes(), rrtype).is_none());
self.type_names.insert(rrtype, name); self.type_names.insert(rrtype, name);
} }
@ -156,10 +195,17 @@ impl Registry {
self.register_name(name, rrtype); self.register_name(name, rrtype);
} }
fn register_known<T: StaticRRData>(&mut self) { fn register_known<T: StaticRRData + Sync + 'static>(&mut self) {
let rrtype = T::TYPE; let rrtype = T::TYPE;
let name = T::NAME; let name = T::NAME;
self.register_name(name, rrtype); self.register_name(name, rrtype);
self.type_parser.insert(rrtype, ()); self.type_parser.insert(rrtype, Box::new(TagRRDataType::<T>(PhantomData)));
}
fn check_registration<T: StaticRRData + Sync + 'static>(&self) {
assert_eq!(self.names_to_type.get(T::NAME.as_bytes()), Some(&T::TYPE));
let p: &RRDataTypeParse = &**self.type_parser.get(&T::TYPE).expect("no parser registered");
let tid = TypeId::of::<TagRRDataType<T>>();
assert_eq!(p.type_id(), tid);
} }
} }

View File

@ -7,38 +7,38 @@ use std::net::{Ipv4Addr, Ipv6Addr};
// registered; there must be a records::types::$name `Type` constant // registered; there must be a records::types::$name `Type` constant
// with the same name as the struct. // with the same name as the struct.
// class IN
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(IN)]
pub struct A { pub struct A {
addr: Ipv4Addr, addr: Ipv4Addr,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct NS { pub struct NS {
nsdname: DnsCompressedName, nsdname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MD { pub struct MD {
madname: DnsCompressedName, madname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MF { pub struct MF {
madname: DnsCompressedName, madname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct CNAME { pub struct CNAME {
cname: DnsCompressedName, cname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct SOA { pub struct SOA {
mname: DnsCompressedName, mname: DnsCompressedName,
rname: DnsCompressedName, rname: DnsCompressedName,
@ -49,84 +49,86 @@ pub struct SOA {
minimum: u32, minimum: u32,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MB { pub struct MB {
madname: DnsCompressedName, madname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MG { pub struct MG {
mgmname: DnsCompressedName, mgmname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MR { pub struct MR {
newname: DnsCompressedName, newname: DnsCompressedName,
} }
// not allowed in zone files anyway, i.e. no text representation. // not allowed in zone files anyway, i.e. no text representation.
// content not restricted either, just some bytes. no need to parse it. // content not restricted either, just some bytes. no need to parse it,
// generic representation should be just fine.
// //
// class independent pub struct NULL; // #[RRClass(ANY)]
// pub struct NULL;
// text representation like: `WKS 127.0.0.1 TCP smtp http 110`. would // text representation like: `WKS 127.0.0.1 TCP smtp http 110`. would
// have to parse protocol and service names. // have to parse protocol and service names.
// //
// class IN
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(IN)]
// pub struct WKS { // pub struct WKS {
// address: Ipv4Addr, // address: Ipv4Addr,
// protocol: u8, // protocol: u8,
// bitmap: ..., // remaining bytes // bitmap: ..., // remaining bytes
// } // }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct PTR { pub struct PTR {
ptrdname: DnsCompressedName, ptrdname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct HINFO { pub struct HINFO {
cpu: ShortText, cpu: ShortText,
os: ShortText, os: ShortText,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MINFO { pub struct MINFO {
rmailbx: DnsCompressedName, rmailbx: DnsCompressedName,
emailbx: DnsCompressedName, emailbx: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct MX { pub struct MX {
preference: u16, preference: u16,
mxname: DnsCompressedName, mxname: DnsCompressedName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct TXT { pub struct TXT {
text: LongText, text: LongText,
} }
// end of RFC 1035: no DnsCompressedName below! // end of RFC 1035: no DnsCompressedName below!
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct RP { pub struct RP {
mbox: DnsCanonicalName, mbox: DnsCanonicalName,
txt: DnsCanonicalName, txt: DnsCanonicalName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct AFSDB { pub struct AFSDB {
subtype: u16, subtype: u16,
hostname: DnsCanonicalName, hostname: DnsCanonicalName,
@ -142,35 +144,37 @@ pub struct AFSDB {
// least 4 bytes in the field: probably due to "beginning with the 4 // least 4 bytes in the field: probably due to "beginning with the 4
// digit DNIC"). // digit DNIC").
// //
// class independent // #[RRClass(ANY)]
// pub struct X25 { // pub struct X25 {
// psdn_address: ShortText, // psdn_address: ShortText,
// } // }
// class independent // #[RRClass(ANY)]
// pub struct ISDN { // pub struct ISDN {
// isdn_address: ShortText, // isdn_address: ShortText,
// subaddress: Option<ShortText>, // subaddress: Option<ShortText>,
// } // }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct RT { pub struct RT {
preference: u16, preference: u16,
intermediate: DnsCanonicalName, intermediate: DnsCanonicalName,
} }
// #[RRClass(ANY)]
// pub struct NSAP; // pub struct NSAP;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRTypeName = "NSAP-PTR"] #[RRTypeName = "NSAP-PTR"]
#[RRClass(ANY)]
pub struct NSAP_PTR { pub struct NSAP_PTR {
owner: DnsCanonicalName, owner: DnsCanonicalName,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct SIG { pub struct SIG {
rr_type: Type, rr_type: Type,
algorithm: u8, algorithm: u8,
@ -186,8 +190,8 @@ pub struct SIG {
signature: Base64RemainingBlob, signature: Base64RemainingBlob,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct KEY { pub struct KEY {
flags: u16, flags: u16,
protocol: u8, protocol: u8,
@ -195,18 +199,24 @@ pub struct KEY {
public_key: Base64RemainingBlob, public_key: Base64RemainingBlob,
} }
// class IN
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(IN)]
pub struct PX { pub struct PX {
preference: u16, preference: u16,
map822: DnsCanonicalName, map822: DnsCanonicalName,
mapx400: DnsCanonicalName, mapx400: DnsCanonicalName,
} }
// pub struct GPOS;
// class IN
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)] // not restricted in rfc 1712
pub struct GPOS {
longitude: ShortText,
latitude: ShortText,
altitude: ShortText,
}
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(IN)]
pub struct AAAA { pub struct AAAA {
addr: Ipv6Addr, addr: Ipv6Addr,
} }
@ -214,16 +224,22 @@ pub struct AAAA {
pub use super::weird_structs::LOC; pub use super::weird_structs::LOC;
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct NXT { pub struct NXT {
next: DnsCanonicalName, next: DnsCanonicalName,
types: NxtTypeBitmap, types: NxtTypeBitmap,
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct EID; // pub struct EID;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct NIMLOC; // pub struct NIMLOC;
// class IN
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(IN)]
pub struct SRV { pub struct SRV {
preference: u16, preference: u16,
weight: u16, weight: u16,
@ -231,10 +247,12 @@ pub struct SRV {
target: DnsCanonicalName, target: DnsCanonicalName,
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct ATMA; // pub struct ATMA;
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct NAPTR { pub struct NAPTR {
order: u16, order: u16,
preference: u16, preference: u16,
@ -244,15 +262,15 @@ pub struct NAPTR {
replacement: DnsCanonicalName, replacement: DnsCanonicalName,
} }
// class IN
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(IN)]
pub struct KX { pub struct KX {
preference: u16, preference: u16,
exchanger: DnsCanonicalName, exchanger: DnsCanonicalName,
} }
// class ??
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
pub struct CERT { pub struct CERT {
cert_type: u16, cert_type: u16,
key_tag: u16, key_tag: u16,
@ -262,21 +280,26 @@ pub struct CERT {
pub use super::weird_structs::A6; pub use super::weird_structs::A6;
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct DNAME { pub struct DNAME {
target: DnsCanonicalName, target: DnsCanonicalName,
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct SINK; // pub struct SINK;
// OPT should be decoded at "transport level", abuses ttl and class // OPT should be decoded at "transport level", abuses ttl and class
// fields too. // fields too.
// pub struct OPT; // pub struct OPT;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct APL; // pub struct APL;
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct DS { pub struct DS {
key_tag: u16, key_tag: u16,
algorithm: u8, algorithm: u8,
@ -285,6 +308,7 @@ pub struct DS {
} }
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
pub struct SSHFP { pub struct SSHFP {
algorithm: u8, algorithm: u8,
fingerprint_type: u8, fingerprint_type: u8,
@ -294,10 +318,11 @@ pub struct SSHFP {
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct IPSECKEY; // pub struct IPSECKEY;
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct RRSIG { pub struct RRSIG {
rr_type: Type, rr_type: Type,
algorithm: u8, algorithm: u8,
@ -310,15 +335,15 @@ pub struct RRSIG {
signature: Base64RemainingBlob, signature: Base64RemainingBlob,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct NSEC { pub struct NSEC {
next: DnsCanonicalName, next: DnsName, // RFC 6840 says not canonic (updates RFC 4034)
types: NsecTypeBitmap, types: NsecTypeBitmap,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct DNSKEY { pub struct DNSKEY {
flags: u16, flags: u16,
protocol: u8, protocol: u8,
@ -327,10 +352,11 @@ pub struct DNSKEY {
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct DHCID; // pub struct DHCID;
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct NSEC3 { pub struct NSEC3 {
hash_algorithm: u8, hash_algorithm: u8,
flags: u8, flags: u8,
@ -340,8 +366,8 @@ pub struct NSEC3 {
types: NsecTypeBitmap, types: NsecTypeBitmap,
} }
// class independent
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct NSEC3PARAM { pub struct NSEC3PARAM {
hash_algorithm: u8, hash_algorithm: u8,
flags: u8, flags: u8,
@ -350,63 +376,103 @@ pub struct NSEC3PARAM {
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct TLSA; // pub struct TLSA;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct SMIMEA; // pub struct SMIMEA;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct HIP; // pub struct HIP;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct NINFO; // pub struct NINFO;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct RKEY; // pub struct RKEY;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct TALINK; // pub struct TALINK;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct CDS; // pub struct CDS;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct CDNSKEY; // pub struct CDNSKEY;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct OPENPGPKEY; // pub struct OPENPGPKEY;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct CSYNC; // pub struct CSYNC;
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
pub struct SPF { pub struct SPF {
text: LongText, text: LongText,
} }
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct UINFO; // pub struct UINFO;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct UID; // pub struct UID;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct GID; // pub struct GID;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct UNSPEC; // pub struct UNSPEC;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct NID; // pub struct NID;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct L32; // pub struct L32;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct L64; // pub struct L64;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct LP; // pub struct LP;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct EUI48; // pub struct EUI48;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct EUI64; // pub struct EUI64;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct TKEY; // pub struct TKEY;
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
// pub struct TSIG; // pub struct TSIG;
// pub struct IXFR; // qtype only? // QTYPEs: IXFR, AXFR, MAILB, MAILA, ANY
// pub struct AXFR; // qtype only?
// pub struct MAILB; // qtype only?
// pub struct MAILA; // qtype only?
// pub struct ANY; // qtype only?
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
#[RRClass(ANY)]
pub struct URI { pub struct URI {
priority: u16, priority: u16,
weight: u16, weight: u16,
@ -414,6 +480,7 @@ pub struct URI {
} }
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[RRClass(?)]
pub struct CAA { pub struct CAA {
flags: u8, flags: u8,
tag: UnquotedShortText, tag: UnquotedShortText,
@ -426,7 +493,9 @@ pub struct CAA {
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] // #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// pub struct DLV; // pub struct DLV;
// pub struct ADDR; // powerdns
#[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)]
// #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(IN)] // used to lookup A and AAAA - only useful in IN
// pub struct ALIAS; pub struct ALIAS {
content: DnsName,
}

View File

@ -1,4 +1,5 @@
use bytes::{Bytes, Buf}; use bytes::{Bytes, Buf};
use common_types::classes;
use failure::ResultExt; use failure::ResultExt;
use records::structs; use records::structs;
use ser::{packet, text, StaticRRData}; use ser::{packet, text, StaticRRData};
@ -10,7 +11,7 @@ where
T: StaticRRData T: StaticRRData
{ {
let mut data = Cursor::new(Bytes::from_static(data)); let mut data = Cursor::new(Bytes::from_static(data));
let result = T::deserialize_rr_data(3600, 0x0001, T::TYPE, &mut data)?; let result = T::deserialize_rr_data(3600, classes::IN, T::TYPE, &mut data)?;
ensure!(!data.has_remaining(), "rrdata not read completely"); ensure!(!data.has_remaining(), "rrdata not read completely");
Ok(result) Ok(result)
} }

View File

@ -1,11 +1,13 @@
use bytes::Bytes; use bytes::Bytes;
use common_types::*; use common_types::*;
use failure::{ResultExt, Fail};
use ser::text::{DnsTextFormatter, next_field};
use ser::packet::remaining_bytes;
use common_types::binary::HEXLOWER_PERMISSIVE_ALLOW_WS; use common_types::binary::HEXLOWER_PERMISSIVE_ALLOW_WS;
use std::fmt;
use errors::*; use errors::*;
use failure::{ResultExt, Fail};
use ser::packet::remaining_bytes;
use ser::RRDataPacket;
use ser::text::{DnsTextFormatter, next_field};
use std::fmt;
use std::io::Cursor;
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct UnknownRecord { pub struct UnknownRecord {
@ -45,3 +47,9 @@ impl UnknownRecord {
write!(f, "TYPE{} \\# {} {}", self.rr_type.0, self.raw.len(), HEXLOWER_PERMISSIVE_ALLOW_WS.encode(&self.raw)) write!(f, "TYPE{} \\# {} {}", self.rr_type.0, self.raw.len(), HEXLOWER_PERMISSIVE_ALLOW_WS.encode(&self.raw))
} }
} }
impl RRDataPacket for UnknownRecord {
fn deserialize_rr_data(_ttl: u32, _rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> {
UnknownRecord::deserialize(rr_type, data)
}
}

View File

@ -11,8 +11,8 @@ use std::net::Ipv6Addr;
// registered; there must be a records::types::$name `Type` constant // registered; there must be a records::types::$name `Type` constant
// with the same name as the struct. // with the same name as the struct.
// class independent
#[derive(Clone, PartialEq, Eq, Debug, RRData)] #[derive(Clone, PartialEq, Eq, Debug, RRData)]
#[RRClass(ANY)]
pub enum LOC { pub enum LOC {
Version0(LOC0), Version0(LOC0),
UnknownVersion{ UnknownVersion{
@ -56,8 +56,8 @@ pub struct LOC0 {
altitude: u32, altitude: u32,
} }
// class IN
#[derive(Clone, PartialEq, Eq, Debug, RRData)] #[derive(Clone, PartialEq, Eq, Debug, RRData)]
#[RRClass(IN)]
pub struct A6 { pub struct A6 {
prefix: u8, // [0...128] prefix: u8, // [0...128]
// might include non-zero padding // might include non-zero padding

View File

@ -1,24 +1,54 @@
use bytes::Bytes; use bytes::Bytes;
use common_types::Type; use common_types::{Class, Type};
use common_types::classes;
use errors::*; use errors::*;
use std::io::Cursor;
use ser::DnsPacketData; use ser::DnsPacketData;
use ser::text::{DnsTextData, DnsTextFormatter};
use std::fmt;
use std::io::Cursor;
pub trait RRDataPacket: Sized { pub trait RRDataPacket {
fn deserialize_rr_data(ttl: u32, rr_class: u16, 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>
where
Self: Sized,
;
} }
impl<T: DnsPacketData> RRDataPacket for T { impl<T: DnsPacketData + StaticRRData> RRDataPacket for T {
fn deserialize_rr_data(_ttl: u32, _rr_class: u16, _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");
if T::CLASS != classes::ANY {
ensure!(rr_class == T::CLASS, "class mismatch");
}
T::deserialize(data) T::deserialize(data)
} }
} }
pub trait RRData: RRDataPacket + super::DnsTextData { pub trait RRDataText: Sized {
fn dns_parse_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut &str) -> Result<Self>
where
Self: Sized,
;
// format might fail if there is no (known) text representation.
fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result;
}
/*
impl<T: DnsTextData> RRDataText for T {
fn deserialize_rr_data(_ttl: u32, _rr_class: Class, _rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Self> {
T::deserialize(data)
}
}
*/
pub trait RRData: RRDataPacket + DnsTextData {
fn rr_type(&self) -> Type; fn rr_type(&self) -> Type;
} }
pub trait StaticRRData: RRData { pub trait StaticRRData: RRData {
const TYPE: Type; const TYPE: Type;
const NAME: &'static str; const NAME: &'static str;
// classes::ANY marks class independent types
const CLASS: Class;
} }

View File

@ -94,8 +94,11 @@ impl<'a> DnsTextFormatter<'a> {
} }
} }
pub trait DnsTextData: Sized { pub trait DnsTextData {
fn dns_parse(data: &mut &str) -> ::errors::Result<Self>; fn dns_parse(data: &mut &str) -> ::errors::Result<Self>
where
Self: Sized,
;
// format might fail if there is no (known) text representation. // format might fail if there is no (known) text representation.
fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result; fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result;
} }

View File

@ -51,7 +51,7 @@ pub fn derive_dns_text_data(input: TokenStream) -> TokenStream {
gen.parse().unwrap() gen.parse().unwrap()
} }
#[proc_macro_derive(RRData, attributes(RRTypeName))] #[proc_macro_derive(RRData, attributes(RRTypeName, RRClass))]
pub fn derive_rr_data(input: TokenStream) -> TokenStream { pub fn derive_rr_data(input: TokenStream) -> TokenStream {
let s = input.to_string(); let s = input.to_string();

View File

@ -6,6 +6,7 @@ use super::{attr_get_single_list_arg};
#[derive(Clone,Debug)] #[derive(Clone,Debug)]
enum StructAttribute { enum StructAttribute {
RRTypeName(quote::Tokens), RRTypeName(quote::Tokens),
RRClass(quote::Tokens),
} }
struct StructAttributeParser<'a>(pub &'a [syn::Attribute]); struct StructAttributeParser<'a>(pub &'a [syn::Attribute]);
@ -21,6 +22,9 @@ impl<'a> Iterator for StructAttributeParser<'a> {
"RRTypeName" => { "RRTypeName" => {
return Some(StructAttribute::RRTypeName(attr_get_single_list_arg(a))); return Some(StructAttribute::RRTypeName(attr_get_single_list_arg(a)));
}, },
"RRClass" => {
return Some(StructAttribute::RRClass(attr_get_single_list_arg(a)));
},
_ => (), _ => (),
} }
} }
@ -42,19 +46,29 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
} }
let name = &ast.ident; let name = &ast.ident;
let mut name_str = {
let name_str: &str = name.as_ref(); let mut name_str = None;
quote!{#name_str} let mut rr_class = None;
};
for attr in StructAttributeParser(&ast.attrs) { for attr in StructAttributeParser(&ast.attrs) {
match attr { match attr {
StructAttribute::RRTypeName(name) => { StructAttribute::RRTypeName(name) => {
name_str = name; assert_eq!(name_str, None, "only one RRTypeName attribute allowed");
name_str = Some(name);
},
StructAttribute::RRClass(c) => {
assert_eq!(rr_class, None, "only one RRTypeName attribute allowed");
rr_class = Some(c);
}, },
} }
} }
let name_str = name_str.unwrap_or_else(|| {
let name_str: &str = name.as_ref();
quote!{#name_str}
});
let rr_class = rr_class.unwrap_or_else(|| quote!{ANY});
let test_mod_name = syn::Ident::from(format!("test_rr_{}", name)); let test_mod_name = syn::Ident::from(format!("test_rr_{}", name));
quote!{ quote!{
@ -67,6 +81,7 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
impl ::dnsbox_base::ser::StaticRRData for #name { impl ::dnsbox_base::ser::StaticRRData for #name {
const TYPE: ::dnsbox_base::common_types::Type = ::dnsbox_base::common_types::types::#name; const TYPE: ::dnsbox_base::common_types::Type = ::dnsbox_base::common_types::types::#name;
const NAME: &'static str = #name_str; const NAME: &'static str = #name_str;
const CLASS: ::dnsbox_base::common_types::Class = ::dnsbox_base::common_types::classes::#rr_class;
} }
// #[cfg(test)] // #[cfg(test)]
@ -78,10 +93,7 @@ pub fn build(ast: &syn::DeriveInput) -> quote::Tokens {
#[test] #[test]
fn test_registry() { fn test_registry() {
assert_eq!( registry::check_registration::<#name>();
registry::known_name_to_type(#name::NAME),
Some(types::#name)
);
} }
} }
} }