You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
239 lines
8.3 KiB
239 lines
8.3 KiB
use bytes::Bytes; |
|
use std::any::TypeId; |
|
use std::collections::HashMap; |
|
use std::io::Cursor; |
|
use std::marker::PhantomData; |
|
|
|
use crate::common_types::{Class, Type, types}; |
|
use crate::errors::*; |
|
use crate::records::structs; |
|
use crate::ser::{RRData, StaticRRData}; |
|
use crate::ser::text::DnsTextContext; |
|
|
|
// this should be enough for registered names |
|
const TYPE_NAME_MAX_LEN: usize = 16; |
|
|
|
lazy_static::lazy_static!{ |
|
static ref REGISTRY: Registry = Registry::init(); |
|
} |
|
|
|
fn registry() -> &'static 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> { |
|
let registry = registry(); |
|
let t = lookup_type_name(name)?; |
|
registry.type_parser.get(&t)?; |
|
|
|
Some(t) |
|
} |
|
|
|
pub fn deserialize_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor<Bytes>) -> Result<Box<dyn RRData>> { |
|
let registry = registry(); |
|
match registry.type_parser.get(&rr_type) { |
|
Some(p) => p.deserialize_rr_data(ttl, rr_class, rr_type, data), |
|
None => Ok(Box::new(super::UnknownRecord::deserialize(rr_type, data)?) as _), |
|
} |
|
} |
|
|
|
pub fn parse_rr_data(context: &DnsTextContext, data: &mut &str) -> Result<Box<dyn RRData>> { |
|
let registry = registry(); |
|
let t = match context.record_type() { |
|
Some(t) => t, |
|
None => failure::bail!("require record type to parse record data"), |
|
}; |
|
match registry.type_parser.get(&t) { |
|
Some(p) => p.parse_rr_data(context, data), |
|
None => failure::bail!("unknown type: {}", t), |
|
} |
|
} |
|
|
|
pub(crate) fn lookup_type_to_name(rrtype: Type) -> Option<&'static str> { |
|
let registry = registry(); |
|
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>); |
|
|
|
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<dyn RRData>>; |
|
|
|
fn parse_rr_data(&self, context: &DnsTextContext, data: &mut &str) -> Result<Box<dyn 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<dyn RRData>> { |
|
T::deserialize_rr_data(ttl, rr_class, rr_type, data).map(|d| Box::new(d) as _) |
|
} |
|
|
|
fn parse_rr_data(&self, context: &DnsTextContext, data: &mut &str) -> Result<Box<dyn RRData>> { |
|
T::dns_parse_rr_data(context, data).map(|d| Box::new(d) as _) |
|
} |
|
} |
|
|
|
struct Registry { |
|
// store (ascii) upper-case names. |
|
names_to_type: HashMap<Vec<u8>, Type>, |
|
type_names: HashMap<Type, String>, |
|
type_parser: HashMap<Type, Box<dyn RRDataTypeParse + Sync>>, |
|
// make sure registrations are in order |
|
prev_type: Option<Type>, |
|
} |
|
|
|
impl Registry { |
|
fn init() -> Self { |
|
let mut r = Registry { |
|
names_to_type: HashMap::new(), |
|
type_names: HashMap::new(), |
|
type_parser: HashMap::new(), |
|
prev_type: None, |
|
}; |
|
|
|
r.register_known::<structs::A>(); |
|
r.register_known::<structs::NS>(); |
|
r.register_known::<structs::MD>(); |
|
r.register_known::<structs::MF>(); |
|
r.register_known::<structs::CNAME>(); |
|
r.register_known::<structs::SOA>(); |
|
r.register_known::<structs::MB>(); |
|
r.register_known::<structs::MG>(); |
|
r.register_known::<structs::MR>(); |
|
r.register_unknown("NULL" , types::NULL); |
|
r.register_unknown("WKS" , types::WKS); |
|
r.register_known::<structs::PTR>(); |
|
r.register_known::<structs::HINFO>(); |
|
r.register_known::<structs::MINFO>(); |
|
r.register_known::<structs::MX>(); |
|
r.register_known::<structs::TXT>(); |
|
r.register_known::<structs::RP>(); |
|
r.register_known::<structs::AFSDB>(); |
|
r.register_unknown("X25" , types::X25); |
|
r.register_unknown("ISDN" , types::ISDN); |
|
r.register_known::<structs::RT>(); |
|
r.register_unknown("NSAP" , types::NSAP); |
|
r.register_known::<structs::NSAP_PTR>(); |
|
r.register_known::<structs::SIG>(); |
|
r.register_known::<structs::KEY>(); |
|
r.register_known::<structs::PX>(); |
|
r.register_known::<structs::GPOS>(); |
|
r.register_known::<structs::AAAA>(); |
|
r.register_known::<structs::LOC>(); |
|
r.register_known::<structs::NXT>(); |
|
r.register_unknown("EID" , types::EID); |
|
r.register_unknown("NIMLOC" , types::NIMLOC); |
|
r.register_known::<structs::SRV>(); |
|
r.register_unknown("ATMA" , types::ATMA); |
|
r.register_known::<structs::NAPTR>(); |
|
r.register_known::<structs::KX>(); |
|
r.register_known::<structs::CERT>(); |
|
r.register_known::<structs::A6>(); |
|
r.register_known::<structs::DNAME>(); |
|
r.register_unknown("SINK" , types::SINK); |
|
r.register_unknown("OPT" , types::OPT); |
|
r.register_known::<structs::APL>(); |
|
r.register_known::<structs::DS>(); |
|
r.register_known::<structs::SSHFP>(); |
|
r.register_known::<structs::IPSECKEY>(); |
|
r.register_known::<structs::RRSIG>(); |
|
r.register_known::<structs::NSEC>(); |
|
r.register_known::<structs::DNSKEY>(); |
|
r.register_known::<structs::DHCID>(); |
|
r.register_known::<structs::NSEC3>(); |
|
r.register_known::<structs::NSEC3PARAM>(); |
|
r.register_known::<structs::TLSA>(); |
|
r.register_known::<structs::SMIMEA>(); |
|
r.register_unknown("HIP" , types::HIP); |
|
r.register_known::<structs::NINFO>(); |
|
r.register_known::<structs::RKEY>(); |
|
r.register_unknown("TALINK" , types::TALINK); |
|
r.register_known::<structs::CDS>(); |
|
r.register_known::<structs::CDNSKEY>(); |
|
r.register_known::<structs::OPENPGPKEY>(); |
|
r.register_unknown("CSYNC" , types::CSYNC); |
|
r.register_unknown("ZONEMD" , types::ZONEMD); |
|
r.register_known::<structs::SPF>(); |
|
r.register_unknown("UINFO" , types::UINFO); |
|
r.register_unknown("UID" , types::UID); |
|
r.register_unknown("GID" , types::GID); |
|
r.register_unknown("UNSPEC" , types::UNSPEC); |
|
r.register_unknown("NID" , types::NID); |
|
r.register_unknown("L32" , types::L32); |
|
r.register_unknown("L64" , types::L64); |
|
r.register_unknown("LP" , types::LP); |
|
r.register_known::<structs::EUI48>(); |
|
r.register_known::<structs::EUI64>(); |
|
r.register_known::<structs::TKEY>(); |
|
r.register_known::<structs::TSIG>(); |
|
r.register_unknown("IXFR" , types::IXFR); |
|
r.register_unknown("AXFR" , types::AXFR); |
|
r.register_unknown("MAILB" , types::MAILB); |
|
r.register_unknown("MAILA" , types::MAILA); |
|
r.register_unknown("ANY" , types::ANY); |
|
r.register_known::<structs::URI>(); |
|
r.register_known::<structs::CAA>(); |
|
r.register_unknown("AVC" , types::AVC); |
|
r.register_unknown("DOA" , types::DOA); |
|
r.register_unknown("AMTRELAY" , types::AMTRELAY); |
|
r.register_unknown("TA" , types::TA); |
|
r.register_known::<structs::DLV>(); |
|
r.register_known::<structs::ALIAS>(); |
|
|
|
// "ALL" could be an alias for the ANY type? |
|
// assert!(r.names_to_type.insert("ALL".into(), types::ANY).is_none()); |
|
|
|
r |
|
} |
|
|
|
fn register_name(&mut self, name: &str, rrtype: Type) { |
|
assert!(self.prev_type < Some(rrtype), "registration not in order"); |
|
self.prev_type = Some(rrtype); |
|
let mut name: String = name.into(); |
|
name.make_ascii_uppercase(); |
|
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); |
|
} |
|
|
|
fn register_unknown(&mut self, name: &'static str, rrtype: Type) { |
|
self.register_name(name, rrtype); |
|
} |
|
|
|
fn register_known<T: StaticRRData + Sync + 'static>(&mut self) { |
|
let rrtype = T::TYPE; |
|
let name = T::NAME; |
|
self.register_name(name, 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: &dyn RRDataTypeParse = &**self.type_parser.get(&T::TYPE).expect("no parser registered"); |
|
let tid = TypeId::of::<TagRRDataType<T>>(); |
|
assert_eq!(p.type_id(), tid); |
|
} |
|
}
|
|
|