diff --git a/dnsbox/src/bin/resolver/cache/mod.rs b/dnsbox/src/bin/resolver/cache/mod.rs index 1f5410e..749a189 100644 --- a/dnsbox/src/bin/resolver/cache/mod.rs +++ b/dnsbox/src/bin/resolver/cache/mod.rs @@ -1,8 +1,8 @@ -use dnsbox_base::common_types::{Type, DnsName}; -use failure::Error; +use dnsbox_base::common_types::{DnsName, Type}; use dnsbox_base::ser::RRData; -use futures::{Future, Poll, Async}; +use failure::Error; use futures::unsync::oneshot; +use futures::{Async, Future, Poll}; use std::cell::RefCell; use std::collections::HashMap; use std::mem::replace; @@ -82,13 +82,13 @@ impl InnerEntry { replace(self, InnerEntry::Refreshing(e)); (false, res) } - } + }, InnerEntry::Pending(mut queue) => { let (tx, rx) = oneshot::channel(); queue.push(tx); replace(self, InnerEntry::Pending(queue)); (false, CacheResult(InnerResult::Waiting(rx))) - } + }, } } } @@ -135,9 +135,9 @@ impl Cache { } /// Insert hints - /// + /// /// # Panics - /// + /// /// Panics when the `rrset` entries don't match `rrtype`. pub fn insert_hint(&self, name: DnsName, rrtype: Type, rrset: Vec>) { for e in &rrset { @@ -168,7 +168,7 @@ impl Future for CacheResult { // keep waiting replace(&mut self.0, InnerResult::Waiting(rc)); Ok(Async::NotReady) - } + }, } }, InnerResult::Finished => Ok(Async::NotReady), diff --git a/dnsbox/src/bin/resolver/cache/root_hints.rs b/dnsbox/src/bin/resolver/cache/root_hints.rs index c957ebb..c5c2890 100644 --- a/dnsbox/src/bin/resolver/cache/root_hints.rs +++ b/dnsbox/src/bin/resolver/cache/root_hints.rs @@ -1,6 +1,6 @@ -use dnsbox_base::common_types::{types}; -use dnsbox_base::common_types::{DnsName, DnsCompressedName}; -use dnsbox_base::records::{NS, A, AAAA}; +use dnsbox_base::common_types::types; +use dnsbox_base::common_types::{DnsCompressedName, DnsName}; +use dnsbox_base::records::{A, AAAA, NS}; use dnsbox_base::ser::RRData; use std::net::{Ipv4Addr, Ipv6Addr}; @@ -26,13 +26,21 @@ pub fn load_hints(cache: &super::Cache) { for &(name, ipv4, ipv6) in &DATA { let name = name.parse::().expect("invalid root hint name"); - let ipv4 = ipv4.parse::().expect("invalid root hint ipv4 addr"); - let ipv6 = ipv6.parse::().expect("invalid root hint ipv6 addr"); + let ipv4 = ipv4 + .parse::() + .expect("invalid root hint ipv4 addr"); + let ipv6 = ipv6 + .parse::() + .expect("invalid root hint ipv6 addr"); root_ns_set.push(Box::new(NS { nsdname: DnsCompressedName(name.clone()), })); cache.insert_hint(name.clone(), types::A, vec![Box::new(A { addr: ipv4 })]); - cache.insert_hint(name.clone(), types::AAAA, vec![Box::new(AAAA { addr: ipv6 })]); + cache.insert_hint( + name.clone(), + types::AAAA, + vec![Box::new(AAAA { addr: ipv6 })], + ); } cache.insert_hint(DnsName::new_root(), types::NS, root_ns_set); diff --git a/lib/dnsbox-base/src/common_types/binary.rs b/lib/dnsbox-base/src/common_types/binary.rs index 027fb80..75a9ba6 100644 --- a/lib/dnsbox-base/src/common_types/binary.rs +++ b/lib/dnsbox-base/src/common_types/binary.rs @@ -1,15 +1,17 @@ -use bytes::{Bytes, BufMut}; -use data_encoding::{self, HEXLOWER_PERMISSIVE}; use crate::errors::*; -use failure::{Fail, ResultExt}; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, short_blob, write_short_blob, get_blob}; +use crate::ser::packet::{ + get_blob, remaining_bytes, short_blob, write_short_blob, DnsPacketData, DnsPacketWriteContext, +}; use crate::ser::text::*; +use bytes::{BufMut, Bytes}; +use data_encoding::{self, HEXLOWER_PERMISSIVE}; +use failure::{Fail, ResultExt}; use std::fmt; use std::io::Cursor; static WHITESPACE: &str = "\t\n\x0c\r "; // \f == \x0c formfeed -lazy_static::lazy_static!{ +lazy_static::lazy_static! { pub(crate) static ref HEXLOWER_PERMISSIVE_ALLOW_WS: data_encoding::Encoding = { let mut spec = data_encoding::Specification::new(); spec.symbols.push_str("0123456789abcdef"); @@ -35,7 +37,10 @@ pub struct HexShortBlob(Bytes); impl HexShortBlob { pub fn new(data: Vec) -> Result { - failure::ensure!(data.len() < 256, "short hex blob must be at most 255 bytes long"); + failure::ensure!( + data.len() < 256, + "short hex blob must be at most 255 bytes long" + ); Ok(Self(data.into())) } } @@ -56,9 +61,13 @@ impl DnsTextData for HexShortBlob { if s == "-" { Ok(HexShortBlob(Bytes::new())) } else { - let raw = HEXLOWER_PERMISSIVE.decode(s.as_bytes()) + let raw = HEXLOWER_PERMISSIVE + .decode(s.as_bytes()) .with_context(|e| e.context(format!("invalid hex: {:?}", s)))?; - failure::ensure!(raw.len() < 256, "short hex field must be at most 255 bytes long"); + failure::ensure!( + raw.len() < 256, + "short hex field must be at most 255 bytes long" + ); Ok(HexShortBlob(raw.into())) } } @@ -82,14 +91,17 @@ impl std::ops::Deref for HexShortBlob { // 16-bit length, uses decimal length + base64 encoding (if length > 0) // for text representation. -// +// // In base64 encoding no whitespace allowed and padding required. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Base64LongBlob(Bytes); impl Base64LongBlob { pub fn new(data: Vec) -> Result { - failure::ensure!(data.len() < 0x1_0000, "long base64 blob must be at most 65535 bytes long"); + failure::ensure!( + data.len() < 0x1_0000, + "long base64 blob must be at most 65535 bytes long" + ); Ok(Self(data.into())) } } @@ -115,12 +127,14 @@ impl DnsPacketData for Base64LongBlob { impl DnsTextData for Base64LongBlob { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result { let length_field = next_field(data)?; - let length = length_field.parse::() + let length = length_field + .parse::() .with_context(|_| format!("invalid length for blob: {:?}", length_field))?; if length > 0 { let blob_field = next_field(data)?; - let result = BASE64_ALLOW_WS.decode(blob_field.as_bytes()) + let result = BASE64_ALLOW_WS + .decode(blob_field.as_bytes()) .with_context(|e| e.context(format!("invalid base64: {:?}", blob_field)))?; Ok(Base64LongBlob(result.into())) } else { @@ -129,7 +143,9 @@ impl DnsTextData for Base64LongBlob { } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { - if self.0.len() >= 0x1_0000 { return Err(fmt::Error); } + if self.0.len() >= 0x1_0000 { + return Err(fmt::Error); + } if self.0.is_empty() { write!(f, "0") } else { @@ -175,7 +191,8 @@ impl DnsPacketData for Base64RemainingBlob { impl DnsTextData for Base64RemainingBlob { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result { skip_whitespace(data); - let result = BASE64_ALLOW_WS.decode(data.as_bytes()) + let result = BASE64_ALLOW_WS + .decode(data.as_bytes()) .with_context(|e| e.context(format!("invalid base64: {:?}", data)))?; *data = ""; Ok(Base64RemainingBlob(result.into())) @@ -226,7 +243,8 @@ impl DnsPacketData for HexRemainingBlob { impl DnsTextData for HexRemainingBlob { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result { skip_whitespace(data); - let result = HEXLOWER_PERMISSIVE_ALLOW_WS.decode(data.as_bytes()) + let result = HEXLOWER_PERMISSIVE_ALLOW_WS + .decode(data.as_bytes()) .with_context(|e| e.context(format!("invalid hex: {:?}", data)))?; *data = ""; Ok(HexRemainingBlob(result.into())) @@ -279,7 +297,8 @@ impl DnsPacketData for HexRemainingBlobNotEmpty { impl DnsTextData for HexRemainingBlobNotEmpty { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result { skip_whitespace(data); - let result = HEXLOWER_PERMISSIVE_ALLOW_WS.decode(data.as_bytes()) + let result = HEXLOWER_PERMISSIVE_ALLOW_WS + .decode(data.as_bytes()) .with_context(|e| e.context(format!("invalid hex: {:?}", data)))?; *data = ""; failure::ensure!(!result.is_empty(), "must not be empty"); @@ -287,7 +306,9 @@ impl DnsTextData for HexRemainingBlobNotEmpty { } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { - if self.0.is_empty() { return Err(fmt::Error); } + if self.0.is_empty() { + return Err(fmt::Error); + } write!(f, "{}", HEXLOWER_PERMISSIVE_ALLOW_WS.encode(&self.0)) } } diff --git a/lib/dnsbox-base/src/common_types/dnssec.rs b/lib/dnsbox-base/src/common_types/dnssec.rs index e00857f..7a71db1 100644 --- a/lib/dnsbox-base/src/common_types/dnssec.rs +++ b/lib/dnsbox-base/src/common_types/dnssec.rs @@ -18,7 +18,6 @@ pub enum DnsSecAlgorithm { DSA = 3, // Reserved: 4 [RFC6725] - /// RSA/SHA-1 // [RFC3110][RFC4034] RSASHA1 = 5, @@ -33,13 +32,11 @@ pub enum DnsSecAlgorithm { RSASHA256 = 8, // Reserved: 9 [RFC6725] - /// RSA/SHA-512 // [RFC5702][proposed standard] RSASHA512 = 10, // Reserved: 11 [RFC6725] - /// GOST R 34.10-2001 // [RFC5933][standards track] ECC_GOST = 12, @@ -64,7 +61,6 @@ pub enum DnsSecAlgorithm { /// private algorithm OID // [RFC4034] PRIVATEOID = 254, - // Reserved: 255 [RFC4034][proposed standard] } @@ -94,10 +90,10 @@ pub enum DnskeyProtocol { #[derive(DnsPacketData, DnsTextData)] pub enum DnsSecDigestAlgorithm { // Reserved: 0 [RFC3658] - SHA1 = 0x01, // [RFC3658] - SHA256 = 0x02, // [RFC4509] + SHA1 = 0x01, // [RFC3658] + SHA256 = 0x02, // [RFC4509] GOST_R_34_11_94 = 0x03, // [RFC5933] - SHA384 = 0x04, // [RFC6605] + SHA384 = 0x04, // [RFC6605] } // https://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml diff --git a/lib/dnsbox-base/src/common_types/eui.rs b/lib/dnsbox-base/src/common_types/eui.rs index 51314cb..1f1a512 100644 --- a/lib/dnsbox-base/src/common_types/eui.rs +++ b/lib/dnsbox-base/src/common_types/eui.rs @@ -1,7 +1,7 @@ -use bytes::Bytes; use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; +use crate::ser::text::{next_field, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; use std::fmt; use std::io::{Cursor, Read}; @@ -16,7 +16,11 @@ fn fmt_eui_hyphens(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { fn parse_eui_hyphens(dest: &mut [u8], source: &str) -> Result<()> { let mut pos = 0; for octet in source.split('-') { - failure::ensure!(pos < dest.len(), "too many octets for EUI{}", dest.len() * 8); + failure::ensure!( + pos < dest.len(), + "too many octets for EUI{}", + dest.len() * 8 + ); failure::ensure!(octet.len() == 2, "invalid octet {:?}", octet); match u8::from_str_radix(octet, 16) { Ok(o) => { @@ -28,7 +32,11 @@ fn parse_eui_hyphens(dest: &mut [u8], source: &str) -> Result<()> { }, } } - failure::ensure!(pos == dest.len(), "not enough octets for EUI{}", dest.len() * 8); + failure::ensure!( + pos == dest.len(), + "not enough octets for EUI{}", + dest.len() * 8 + ); Ok(()) } diff --git a/lib/dnsbox-base/src/common_types/mod.rs b/lib/dnsbox-base/src/common_types/mod.rs index 881b930..025e86b 100644 --- a/lib/dnsbox-base/src/common_types/mod.rs +++ b/lib/dnsbox-base/src/common_types/mod.rs @@ -1,71 +1,35 @@ pub mod binary; -pub mod classes; -pub mod name; -pub mod text; -pub mod types; mod caa; +pub mod classes; mod dnssec; mod eui; +pub mod name; mod nsec; mod nxt; mod sig; mod sshfp; +pub mod text; mod time; +pub mod types; mod uri; pub use self::binary::{ - Base64LongBlob, - Base64RemainingBlob, - HexRemainingBlob, - HexRemainingBlobNotEmpty, - HexShortBlob, + Base64LongBlob, Base64RemainingBlob, HexRemainingBlob, HexRemainingBlobNotEmpty, HexShortBlob, }; -pub use self::classes::Class; pub use self::caa::CaaFlags; +pub use self::classes::Class; pub use self::dnssec::{ - DnskeyFlags, - DnskeyProtocol, - DnskeyProtocolKnown, - DnsSecAlgorithm, - DnsSecAlgorithmKnown, - DnsSecDigestAlgorithm, - DnsSecDigestAlgorithmKnown, - Nsec3Algorithm, - Nsec3AlgorithmKnown, - Nsec3Flags, - Nsec3ParamFlags, -}; -pub use self::eui::{ - EUI48Addr, - EUI64Addr, -}; -pub use self::name::{ - DnsCanonicalName, - DnsCompressedName, - DnsName, -}; -pub use self::nsec::{ - NextHashedOwnerName, - NsecTypeBitmap, + DnsSecAlgorithm, DnsSecAlgorithmKnown, DnsSecDigestAlgorithm, DnsSecDigestAlgorithmKnown, + DnskeyFlags, DnskeyProtocol, DnskeyProtocolKnown, Nsec3Algorithm, Nsec3AlgorithmKnown, + Nsec3Flags, Nsec3ParamFlags, }; +pub use self::eui::{EUI48Addr, EUI64Addr}; +pub use self::name::{DnsCanonicalName, DnsCompressedName, DnsName}; +pub use self::nsec::{NextHashedOwnerName, NsecTypeBitmap}; pub use self::nxt::NxtTypeBitmap; pub use self::sig::OptionalTTL; -pub use self::sshfp::{ - SshFpAlgorithm, - SshFpAlgorithmKnown, - SshFpType, - SshFpTypeKnown, -}; -pub use self::text::{ - LongText, - RemainingText, - ShortText, - UnquotedShortText, -}; -pub use self::time::{ - Time, - Time48, - TimeStrict, -}; +pub use self::sshfp::{SshFpAlgorithm, SshFpAlgorithmKnown, SshFpType, SshFpTypeKnown}; +pub use self::text::{LongText, RemainingText, ShortText, UnquotedShortText}; +pub use self::time::{Time, Time48, TimeStrict}; pub use self::types::Type; pub use self::uri::UriText; diff --git a/lib/dnsbox-base/src/common_types/name/canonical_name.rs b/lib/dnsbox-base/src/common_types/name/canonical_name.rs index 7abdbbc..08f1790 100644 --- a/lib/dnsbox-base/src/common_types/name/canonical_name.rs +++ b/lib/dnsbox-base/src/common_types/name/canonical_name.rs @@ -1,13 +1,13 @@ -use bytes::Bytes; use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field, parse_with}; +use crate::ser::text::{next_field, parse_with, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; use std::fmt; use std::io::Cursor; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use super::{DnsName, DnsNameIterator, DnsLabelRef}; +use super::{DnsLabelRef, DnsName, DnsNameIterator}; /// names that should be written in canonical form for DNSSEC according /// to https://tools.ietf.org/html/rfc4034#section-6.2 @@ -24,8 +24,7 @@ impl DnsCanonicalName { } /// Parse text representation of a domain name - pub fn parse(context: &DnsTextContext, value: &str) -> Result - { + pub fn parse(context: &DnsTextContext, value: &str) -> Result { Ok(DnsCanonicalName(DnsName::parse(context, value)?)) } } @@ -65,8 +64,7 @@ impl<'a> IntoIterator for &'a DnsCanonicalName { } } -impl PartialEq for DnsCanonicalName -{ +impl PartialEq for DnsCanonicalName { fn eq(&self, rhs: &DnsName) -> bool { let this: &DnsName = self; this == rhs @@ -75,7 +73,7 @@ impl PartialEq for DnsCanonicalName impl PartialEq for DnsCanonicalName where - T: AsRef + T: AsRef, { fn eq(&self, rhs: &T) -> bool { let this: &DnsName = self.as_ref(); @@ -83,7 +81,7 @@ where } } -impl Eq for DnsCanonicalName{} +impl Eq for DnsCanonicalName {} impl fmt::Debug for DnsCanonicalName { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { @@ -101,7 +99,9 @@ impl FromStr for DnsCanonicalName { type Err = ::failure::Error; fn from_str(s: &str) -> Result { - parse_with(s, |data| DnsCanonicalName::dns_parse(&DnsTextContext::new(), data)) + parse_with(s, |data| { + DnsCanonicalName::dns_parse(&DnsTextContext::new(), data) + }) } } @@ -118,7 +118,9 @@ impl DnsTextData for DnsCanonicalName { impl DnsPacketData for DnsCanonicalName { fn deserialize(data: &mut Cursor) -> Result { - Ok(DnsCanonicalName(super::name_packet_parser::deserialize_name(data, false)?)) + Ok(DnsCanonicalName( + super::name_packet_parser::deserialize_name(data, false)?, + )) } fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { diff --git a/lib/dnsbox-base/src/common_types/name/compressed_name.rs b/lib/dnsbox-base/src/common_types/name/compressed_name.rs index cd4bf7e..800089d 100644 --- a/lib/dnsbox-base/src/common_types/name/compressed_name.rs +++ b/lib/dnsbox-base/src/common_types/name/compressed_name.rs @@ -1,13 +1,13 @@ -use bytes::Bytes; use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field, parse_with}; +use crate::ser::text::{next_field, parse_with, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; use std::fmt; use std::io::Cursor; use std::ops::{Deref, DerefMut}; use std::str::FromStr; -use super::{DnsName, DnsNameIterator, DnsLabelRef}; +use super::{DnsLabelRef, DnsName, DnsNameIterator}; /// Similar to `DnsName`, but allows using compressed labels in the /// serialized form @@ -21,8 +21,7 @@ impl DnsCompressedName { } /// Parse text representation of a domain name - pub fn parse(context: &DnsTextContext, value: &str) -> Result - { + pub fn parse(context: &DnsTextContext, value: &str) -> Result { Ok(DnsCompressedName(DnsName::parse(context, value)?)) } } @@ -62,8 +61,7 @@ impl<'a> IntoIterator for &'a DnsCompressedName { } } -impl PartialEq for DnsCompressedName -{ +impl PartialEq for DnsCompressedName { fn eq(&self, rhs: &DnsName) -> bool { let this: &DnsName = self; this == rhs @@ -72,7 +70,7 @@ impl PartialEq for DnsCompressedName impl PartialEq for DnsCompressedName where - T: AsRef + T: AsRef, { fn eq(&self, rhs: &T) -> bool { let this: &DnsName = self.as_ref(); @@ -80,7 +78,7 @@ where } } -impl Eq for DnsCompressedName{} +impl Eq for DnsCompressedName {} impl fmt::Debug for DnsCompressedName { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { @@ -98,7 +96,9 @@ impl FromStr for DnsCompressedName { type Err = ::failure::Error; fn from_str(s: &str) -> Result { - parse_with(s, |data| DnsCompressedName::dns_parse(&DnsTextContext::new(), data)) + parse_with(s, |data| { + DnsCompressedName::dns_parse(&DnsTextContext::new(), data) + }) } } @@ -115,7 +115,9 @@ impl DnsTextData for DnsCompressedName { impl DnsPacketData for DnsCompressedName { fn deserialize(data: &mut Cursor) -> Result { - Ok(DnsCompressedName(super::name_packet_parser::deserialize_name(data, true)?)) + Ok(DnsCompressedName( + super::name_packet_parser::deserialize_name(data, true)?, + )) } fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { diff --git a/lib/dnsbox-base/src/common_types/name/display.rs b/lib/dnsbox-base/src/common_types/name/display.rs index fc8e840..e7d2111 100644 --- a/lib/dnsbox-base/src/common_types/name/display.rs +++ b/lib/dnsbox-base/src/common_types/name/display.rs @@ -1,5 +1,5 @@ -use std::fmt; use super::DnsLabelRef; +use std::fmt; /// Customize formatting of DNS labels /// @@ -7,7 +7,7 @@ use super::DnsLabelRef; /// /// The `Debug` formatters just format as `Display` to a String and then /// format that string as `Debug`. -#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct DisplayLabelsOptions { /// separator to insert between (escaped) labels pub separator: &'static str, @@ -20,7 +20,7 @@ pub struct DisplayLabelsOptions { impl Default for DisplayLabelsOptions { fn default() -> Self { - DisplayLabelsOptions{ + DisplayLabelsOptions { separator: ".", trailing: true, } @@ -38,7 +38,7 @@ impl Default for DisplayLabelsOptions { #[derive(Clone)] pub struct DisplayLabels<'a, I> where - I: IntoIterator>+Clone + I: IntoIterator> + Clone, { /// Label collection to iterate over pub labels: I, @@ -48,7 +48,7 @@ where impl<'a, I> fmt::Debug for DisplayLabels<'a, I> where - I: IntoIterator>+Clone + I: IntoIterator> + Clone, { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { // just escape the display version1 @@ -58,7 +58,7 @@ where impl<'a, I> fmt::Display for DisplayLabels<'a, I> where - I: IntoIterator>+Clone + I: IntoIterator> + Clone, { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { let mut i = self.labels.clone().into_iter(); diff --git a/lib/dnsbox-base/src/common_types/name/label.rs b/lib/dnsbox-base/src/common_types/name/label.rs index 29da63d..aeab163 100644 --- a/lib/dnsbox-base/src/common_types/name/label.rs +++ b/lib/dnsbox-base/src/common_types/name/label.rs @@ -1,7 +1,7 @@ -use bytes::Bytes; use crate::errors::*; -use std::fmt; +use bytes::Bytes; use std::cmp::Ordering; +use std::fmt; #[inline] fn check_label(label: &[u8]) -> Result<()> { @@ -26,12 +26,14 @@ impl DnsLabel { /// Fails when the length doesn't match the requirement `0 < length < 64`. pub fn new(label: Bytes) -> Result { check_label(&label)?; - Ok(DnsLabel{label}) + Ok(DnsLabel { label }) } /// Convert to a representation without storage pub fn as_ref<'a>(&'a self) -> DnsLabelRef<'a> { - DnsLabelRef{label: self.label.as_ref()} + DnsLabelRef { + label: self.label.as_ref(), + } } /// Access as raw bytes @@ -58,7 +60,7 @@ impl DnsLabel { impl<'a> From> for DnsLabel { fn from(label_ref: DnsLabelRef<'a>) -> Self { - DnsLabel{ + DnsLabel { label: Bytes::from(label_ref.label), } } @@ -78,7 +80,7 @@ impl<'a> PartialEq> for DnsLabel { } } -impl Eq for DnsLabel{} +impl Eq for DnsLabel {} impl PartialOrd for DnsLabel { #[inline] @@ -116,7 +118,7 @@ impl fmt::Display for DnsLabel { /// A DNS label (any binary string with `0 < length < 64`) /// /// Storage is provided through lifetime. -#[derive(Clone,Copy)] +#[derive(Clone, Copy)] pub struct DnsLabelRef<'a> { pub(super) label: &'a [u8], // 0 < len < 64 } @@ -127,7 +129,7 @@ impl<'a> DnsLabelRef<'a> { /// Fails when the length doesn't match the requirement `0 < length < 64`. pub fn new(label: &'a [u8]) -> Result { check_label(label)?; - Ok(DnsLabelRef{label}) + Ok(DnsLabelRef { label }) } /// Access as raw bytes @@ -180,7 +182,7 @@ impl<'a> PartialEq for DnsLabelRef<'a> { } } -impl<'a> Eq for DnsLabelRef<'a>{} +impl<'a> Eq for DnsLabelRef<'a> {} impl<'a, 'b> PartialOrd> for DnsLabelRef<'b> { #[inline] @@ -218,7 +220,9 @@ impl<'a> fmt::Display for DnsLabelRef<'a> { if c <= 0x21 || c >= 0x7e || b'.' == c || b'\\' == c { // flush if done < pos { - w.write_str(crate::unsafe_ops::from_utf8_unchecked(&self.label[done..pos]))?; + w.write_str(crate::unsafe_ops::from_utf8_unchecked( + &self.label[done..pos], + ))?; } match c { b'.' => w.write_str(r#"\."#)?, diff --git a/lib/dnsbox-base/src/common_types/name/label_offsets.rs b/lib/dnsbox-base/src/common_types/name/label_offsets.rs index 230a416..cc1248b 100644 --- a/lib/dnsbox-base/src/common_types/name/label_offsets.rs +++ b/lib/dnsbox-base/src/common_types/name/label_offsets.rs @@ -1,6 +1,6 @@ use smallvec::SmallVec; -#[derive(Clone,Copy,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum LabelOffset { LabelStart(u8), PacketStart(u16), @@ -8,10 +8,10 @@ pub enum LabelOffset { // the heap meta data is usually at least 2*usize big; assuming 64-bit // platforms it should be ok to use 16 bytes in the smallvec. -#[derive(Clone,PartialEq,Eq,PartialOrd,Ord,Hash,Debug)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum LabelOffsets { - Uncompressed(SmallVec<[u8;16]>), - Compressed(usize, SmallVec<[LabelOffset;4]>), + Uncompressed(SmallVec<[u8; 16]>), + Compressed(usize, SmallVec<[LabelOffset; 4]>), } impl LabelOffsets { @@ -31,7 +31,7 @@ impl LabelOffsets { LabelOffsets::Compressed(start, ref offs) => match offs[ndx as usize] { LabelOffset::LabelStart(o) => start + (o as usize), LabelOffset::PacketStart(o) => o as usize, - } + }, } } diff --git a/lib/dnsbox-base/src/common_types/name/mod.rs b/lib/dnsbox-base/src/common_types/name/mod.rs index a96e444..33dfc08 100644 --- a/lib/dnsbox-base/src/common_types/name/mod.rs +++ b/lib/dnsbox-base/src/common_types/name/mod.rs @@ -1,8 +1,8 @@ #![deny(missing_docs)] //! Various structs to represents DNS names and labels -use bytes::Bytes; use crate::errors::*; +use bytes::Bytes; use smallvec::SmallVec; use std::io::Cursor; @@ -10,9 +10,9 @@ pub use self::canonical_name::*; pub use self::compressed_name::*; pub use self::display::*; pub use self::label::*; -pub use self::name_iterator::*; -pub use self::name::*; use self::label_offsets::*; +pub use self::name::*; +pub use self::name_iterator::*; mod canonical_name; mod compressed_name; diff --git a/lib/dnsbox-base/src/common_types/name/name.rs b/lib/dnsbox-base/src/common_types/name/name.rs index 56277d2..02001f3 100644 --- a/lib/dnsbox-base/src/common_types/name/name.rs +++ b/lib/dnsbox-base/src/common_types/name/name.rs @@ -1,16 +1,16 @@ -use bytes::Bytes; use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field, parse_with}; +use crate::ser::text::{next_field, parse_with, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; use smallvec::SmallVec; use std::fmt; use std::io::Cursor; use std::str::FromStr; -use super::{LabelOffsets, DnsNameIterator, DnsLabelRef, DnsLabel, DisplayLabels}; +use super::{DisplayLabels, DnsLabel, DnsLabelRef, DnsNameIterator, LabelOffsets}; /// A DNS name -/// +/// /// Uses the "original" raw representation for storage (i.e. can share /// memory with a parsed packet) #[derive(Clone)] @@ -30,7 +30,7 @@ pub struct DnsName { impl DnsName { /// Create new name representing the DNS root (".") pub fn new_root() -> Self { - DnsName{ + DnsName { data: Bytes::new(), label_offsets: LabelOffsets::Uncompressed(SmallVec::new()), total_len: 1, @@ -40,7 +40,7 @@ impl DnsName { /// Create new name representing the DNS root (".") and pre-allocate /// storage pub fn with_capacity(labels: u8, total_len: u8) -> Self { - DnsName{ + DnsName { data: Bytes::with_capacity(total_len as usize), label_offsets: LabelOffsets::Uncompressed(SmallVec::with_capacity(labels as usize)), total_len: 1, @@ -66,7 +66,7 @@ impl DnsName { /// Iterator over the labels (in the order they are stored in memory, /// i.e. top-level name last). pub fn labels<'a>(&'a self) -> DnsNameIterator<'a> { - DnsNameIterator{ + DnsNameIterator { name: &self, front_label: 0, back_label: self.label_offsets.len(), @@ -83,7 +83,9 @@ impl DnsName { let label_len = self.data[pos]; debug_assert!(label_len < 64); let end = pos + 1 + label_len as usize; - DnsLabelRef{label: &self.data[pos + 1..end]} + DnsLabelRef { + label: &self.data[pos + 1..end], + } } /// Return label at index `ndx` @@ -96,7 +98,9 @@ impl DnsName { let label_len = self.data[pos]; debug_assert!(label_len < 64); let end = pos + 1 + label_len as usize; - DnsLabel{label: self.data.slice(pos + 1, end) } + DnsLabel { + label: self.data.slice(pos + 1, end), + } } } @@ -109,42 +113,45 @@ impl<'a> IntoIterator for &'a DnsName { } } -impl PartialEq for DnsName -{ +impl PartialEq for DnsName { fn eq(&self, rhs: &DnsName) -> bool { let a_labels = self.labels(); let b_labels = rhs.labels(); - if a_labels.len() != b_labels.len() { return false; } - a_labels.zip(b_labels).all(|(a,b)| a == b) + if a_labels.len() != b_labels.len() { + return false; + } + a_labels.zip(b_labels).all(|(a, b)| a == b) } } impl PartialEq for DnsName where - T: AsRef + T: AsRef, { fn eq(&self, rhs: &T) -> bool { self == rhs.as_ref() } } -impl Eq for DnsName{} +impl Eq for DnsName {} impl fmt::Debug for DnsName { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { - DisplayLabels{ + DisplayLabels { labels: self, options: Default::default(), - }.fmt(w) + } + .fmt(w) } } impl fmt::Display for DnsName { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { - DisplayLabels{ + DisplayLabels { labels: self, options: Default::default(), - }.fmt(w) + } + .fmt(w) } } diff --git a/lib/dnsbox-base/src/common_types/name/name_iterator.rs b/lib/dnsbox-base/src/common_types/name/name_iterator.rs index a24bf17..e83154e 100644 --- a/lib/dnsbox-base/src/common_types/name/name_iterator.rs +++ b/lib/dnsbox-base/src/common_types/name/name_iterator.rs @@ -1,4 +1,4 @@ -use super::{DnsName, DnsLabelRef}; +use super::{DnsLabelRef, DnsName}; /// Iterator type for [`DnsName::labels`] /// @@ -14,7 +14,9 @@ impl<'a> Iterator for DnsNameIterator<'a> { type Item = DnsLabelRef<'a>; fn next(&mut self) -> Option { - if self.front_label >= self.back_label { return None } + if self.front_label >= self.back_label { + return None; + } let label = self.name.label_ref(self.front_label); self.front_label += 1; Some(label) @@ -38,7 +40,9 @@ impl<'a> ExactSizeIterator for DnsNameIterator<'a> { impl<'a> DoubleEndedIterator for DnsNameIterator<'a> { fn next_back(&mut self) -> Option { - if self.front_label >= self.back_label { return None } + if self.front_label >= self.back_label { + return None; + } self.back_label -= 1; let label = self.name.label_ref(self.back_label); Some(label) diff --git a/lib/dnsbox-base/src/common_types/name/name_mutations.rs b/lib/dnsbox-base/src/common_types/name/name_mutations.rs index 367620d..96b26ff 100644 --- a/lib/dnsbox-base/src/common_types/name/name_mutations.rs +++ b/lib/dnsbox-base/src/common_types/name/name_mutations.rs @@ -1,5 +1,5 @@ -use bytes::{BytesMut,BufMut}; use super::*; +use bytes::{BufMut, BytesMut}; impl DnsName { /// Remove the front label @@ -8,12 +8,16 @@ impl DnsName { pub fn try_pop_front(&mut self) -> bool { match self.label_offsets { LabelOffsets::Uncompressed(ref mut offs) => { - if offs.is_empty() { return false; } + if offs.is_empty() { + return false; + } self.total_len -= self.data[offs[0] as usize] + 1; offs.remove(0); }, LabelOffsets::Compressed(ref mut start_pos, ref mut offs) => { - if offs.is_empty() { return false; } + if offs.is_empty() { + return false; + } match offs[0] { LabelOffset::LabelStart(o) => { let label_space = self.data[*start_pos + o as usize] + 1; @@ -36,7 +40,9 @@ impl DnsName { /// /// Panics if the name was the root (".") pub fn pop_front(&mut self) { - if !self.try_pop_front() { panic!("Cannot pop label from root name") } + if !self.try_pop_front() { + panic!("Cannot pop label from root name") + } } /// Insert a new label at the front @@ -44,12 +50,15 @@ impl DnsName { /// Returns an error if the resulting name would be too long pub fn push_front<'a, L: Into>>(&mut self, label: L) -> Result<()> { let label = label.into(); - if label.len() > 254 - self.total_len { failure::bail!("Cannot append label, resulting name too long") } + if label.len() > 254 - self.total_len { + failure::bail!("Cannot append label, resulting name too long") + } let (mut data, start) = self.reserve(label.len() as usize + 1, 0); let new_label_pos = start - (label.len() + 1) as usize; data[new_label_pos] = label.len(); - data[new_label_pos+1..new_label_pos+1+label.len() as usize].copy_from_slice(label.as_raw()); + data[new_label_pos + 1..new_label_pos + 1 + label.len() as usize] + .copy_from_slice(label.as_raw()); self.data = data.freeze(); self.total_len += label.len() + 1; match self.label_offsets { @@ -68,13 +77,17 @@ impl DnsName { pub fn try_pop_back(&mut self) -> bool { match self.label_offsets { LabelOffsets::Uncompressed(ref mut offs) => { - if offs.is_empty() { return false; } - self.total_len -= self.data[offs[offs.len()-1] as usize] + 1; + if offs.is_empty() { + return false; + } + self.total_len -= self.data[offs[offs.len() - 1] as usize] + 1; offs.pop(); }, LabelOffsets::Compressed(ref mut start_pos, ref mut offs) => { - if offs.is_empty() { return false; } - match offs[offs.len()-1] { + if offs.is_empty() { + return false; + } + match offs[offs.len() - 1] { LabelOffset::LabelStart(o) => { self.total_len -= self.data[*start_pos + o as usize] + 1; }, @@ -94,7 +107,9 @@ impl DnsName { /// /// Panics if the name was the root (".") pub fn pop_back(&mut self) { - if !self.try_pop_back() { panic!("Cannot pop label from root name") } + if !self.try_pop_back() { + panic!("Cannot pop label from root name") + } } /// Insert a new label at the back @@ -102,13 +117,16 @@ impl DnsName { /// Returns an error if the resulting name would be too long pub fn push_back<'a, L: Into>>(&mut self, label: L) -> Result<()> { let label = label.into(); - if label.len() > 254 - self.total_len { failure::bail!("Cannot append label, resulting name too long") } + if label.len() > 254 - self.total_len { + failure::bail!("Cannot append label, resulting name too long") + } let (mut data, start) = self.reserve(0, label.len() as usize + 1); let new_label_pos = start + self.total_len as usize - 1; data[new_label_pos] = label.len(); - data[new_label_pos+1..new_label_pos+1+label.len() as usize].copy_from_slice(label.as_raw()); - data[new_label_pos+1+label.len() as usize] = 0; + data[new_label_pos + 1..new_label_pos + 1 + label.len() as usize] + .copy_from_slice(label.as_raw()); + data[new_label_pos + 1 + label.len() as usize] = 0; self.data = data.freeze(); self.total_len += label.len() + 1; match self.label_offsets { @@ -145,19 +163,22 @@ impl DnsName { let add = new_len - data.len(); data.reserve(add); } - unsafe { data.set_len(new_len); } + unsafe { + data.set_len(new_len); + } data[0] = 0; - return (data, 0) + return (data, 0); } let old_start = label_offsets[0] as usize; // if current "prefix" space (old_start) is bigger than // requested but fits, just increase the prefix - let (prefix, new_len) = if old_start > prefix && self.total_len as usize + old_start + suffix < 256 { - (old_start, self.total_len as usize + old_start + suffix) - } else { - (prefix, new_len) - }; + let (prefix, new_len) = + if old_start > prefix && self.total_len as usize + old_start + suffix < 256 { + (old_start, self.total_len as usize + old_start + suffix) + } else { + (prefix, new_len) + }; // check if we need to reallocate let data = match data { @@ -173,13 +194,14 @@ impl DnsName { Err(data) => Err(data), }; - match data { Ok(mut data) => { if data.len() < new_len { let add = new_len - data.len(); data.reserve(add); - unsafe { data.set_len(new_len); } + unsafe { + data.set_len(new_len); + } } if old_start < prefix { // need more space in front, move back @@ -213,9 +235,12 @@ impl DnsName { }, Err(data) => { let mut new_data = BytesMut::with_capacity(new_len); - unsafe { new_data.set_len(new_len); } + unsafe { + new_data.set_len(new_len); + } // copy old data - new_data[prefix..prefix + self.total_len as usize].copy_from_slice(&data[old_start..old_start+self.total_len as usize]); + new_data[prefix..prefix + self.total_len as usize] + .copy_from_slice(&data[old_start..old_start + self.total_len as usize]); // adjust labels for o in label_offsets.iter_mut() { *o = (*o - old_start as u8) + prefix as u8; @@ -246,7 +271,7 @@ impl DnsName { let new_len = self.total_len as usize + prefix_capacity + suffix_capacity; assert!(new_len < 256); let mut data = BytesMut::with_capacity(new_len); - let mut offsets = SmallVec::<[u8;16]>::with_capacity(label_count); + let mut offsets = SmallVec::<[u8; 16]>::with_capacity(label_count); unsafe { data.set_len(prefix_capacity) } let mut pos = prefix_capacity as u8; @@ -258,7 +283,7 @@ impl DnsName { } data.put_u8(0); - DnsName{ + DnsName { data: data.freeze(), label_offsets: LabelOffsets::Uncompressed(offsets), total_len: self.total_len, diff --git a/lib/dnsbox-base/src/common_types/name/name_packet_parser.rs b/lib/dnsbox-base/src/common_types/name/name_packet_parser.rs index e3ac71b..af016e8 100644 --- a/lib/dnsbox-base/src/common_types/name/name_packet_parser.rs +++ b/lib/dnsbox-base/src/common_types/name/name_packet_parser.rs @@ -1,22 +1,34 @@ -use bytes::Buf; use super::*; +use bytes::Buf; /// `data`: bytes of packet from beginning until at least the end of the name /// `start_pos`: position of first byte of the name /// `uncmpr_offsets`: offsets of uncompressed labels so far /// `label_len`: first compressed label length (`0xc0 | offset-high, offset-low`) /// `total_len`: length of (uncompressed) label encoding so far -fn deserialize_name_compressed_cont(data: Bytes, start_pos: usize, uncmpr_offsets: SmallVec<[u8;16]>, mut total_len: usize, mut label_len: u8) -> Result { - let mut label_offsets = uncmpr_offsets.into_iter() - .map(LabelOffset::LabelStart) - .collect::>(); +fn deserialize_name_compressed_cont( + data: Bytes, + start_pos: usize, + uncmpr_offsets: SmallVec<[u8; 16]>, + mut total_len: usize, + mut label_len: u8, +) -> Result { + let mut label_offsets = uncmpr_offsets + .into_iter() + .map(LabelOffset::LabelStart) + .collect::>(); let mut pos = start_pos + total_len; 'next_compressed: loop { { failure::ensure!(pos + 1 < data.len(), "not enough data for compressed label"); let new_pos = ((label_len as usize & 0x3f) << 8) | (data[pos + 1] as usize); - failure::ensure!(new_pos < pos, "Compressed label offset too big: {} >= {}", new_pos, pos); + failure::ensure!( + new_pos < pos, + "Compressed label offset too big: {} >= {}", + new_pos, + pos + ); pos = new_pos; } @@ -25,19 +37,23 @@ fn deserialize_name_compressed_cont(data: Bytes, start_pos: usize, uncmpr_offset label_len = data[pos]; if 0 == label_len { - return Ok(DnsName{ + return Ok(DnsName { data: data, label_offsets: LabelOffsets::Compressed(start_pos, label_offsets), total_len: total_len as u8 + 1, - }) + }); } - if label_len & 0xc0 == 0xc0 { continue 'next_compressed; } + if label_len & 0xc0 == 0xc0 { + continue 'next_compressed; + } failure::ensure!(label_len < 64, "Invalid label length {}", label_len); total_len += 1 + label_len as usize; // max len 255, but there also needs to be an empty label at the end - if total_len > 254 { failure::bail!("DNS name too long") } + if total_len > 254 { + failure::bail!("DNS name too long") + } label_offsets.push(LabelOffset::PacketStart(pos as u16)); pos += 1 + label_len as usize; @@ -48,22 +64,24 @@ fn deserialize_name_compressed_cont(data: Bytes, start_pos: usize, uncmpr_offset pub fn deserialize_name(data: &mut Cursor, accept_compressed: bool) -> Result { check_enough_data!(data, 1, "DnsName"); let start_pos = data.position() as usize; - let mut total_len : usize = 0; + let mut total_len: usize = 0; let mut label_offsets = SmallVec::new(); loop { check_enough_data!(data, 1, "DnsName label len"); let label_len = data.get_u8() as usize; if 0 == label_len { let end_pos = data.position() as usize; - return Ok(DnsName{ + return Ok(DnsName { data: data.get_ref().slice(start_pos, end_pos), label_offsets: LabelOffsets::Uncompressed(label_offsets), total_len: total_len as u8 + 1, - }) + }); } if label_len & 0xc0 == 0xc0 { // compressed label - if !accept_compressed { failure::bail!("Invalid label compression {}", label_len) } + if !accept_compressed { + failure::bail!("Invalid label compression {}", label_len) + } check_enough_data!(data, 1, "DnsName compressed label target"); // eat second part of compressed label data.get_u8(); @@ -71,13 +89,23 @@ pub fn deserialize_name(data: &mut Cursor, accept_compressed: bool) -> Re let end_pos = data.position() as usize; let data = data.get_ref().slice(0, end_pos); - return deserialize_name_compressed_cont(data, start_pos, label_offsets, total_len, label_len as u8); + return deserialize_name_compressed_cont( + data, + start_pos, + label_offsets, + total_len, + label_len as u8, + ); } label_offsets.push(total_len as u8); - if label_len > 63 { failure::bail!("Invalid label length {}", label_len) } + if label_len > 63 { + failure::bail!("Invalid label length {}", label_len) + } total_len += 1 + label_len; // max len 255, but there also needs to be an empty label at the end - if total_len > 254 { failure::bail!{"DNS name too long"} } + if total_len > 254 { + failure::bail! {"DNS name too long"} + } check_enough_data!(data, label_len, "DnsName label"); data.advance(label_len); } diff --git a/lib/dnsbox-base/src/common_types/name/name_text_parser.rs b/lib/dnsbox-base/src/common_types/name/name_text_parser.rs index c149da1..81c485c 100644 --- a/lib/dnsbox-base/src/common_types/name/name_text_parser.rs +++ b/lib/dnsbox-base/src/common_types/name/name_text_parser.rs @@ -1,11 +1,10 @@ use crate::errors::*; -use crate::ser::text::{DnsTextContext, quoted}; +use crate::ser::text::{quoted, DnsTextContext}; -use super::{DnsName, DnsLabelRef}; +use super::{DnsLabelRef, DnsName}; /// Parse text representation of a domain name -pub fn parse_name(context: &DnsTextContext, value: &str) -> Result -{ +pub fn parse_name(context: &DnsTextContext, value: &str) -> Result { let raw = value.as_bytes(); let mut name = DnsName::new_root(); if raw == b"." { @@ -25,23 +24,42 @@ pub fn parse_name(context: &DnsTextContext, value: &str) -> Result name.push_back(DnsLabelRef::new(&label)?)?; label.clear(); } else if raw[pos] == b'\\' { - failure::ensure!(pos + 1 < raw.len(), "unexpected end of name after backslash: {:?}", value); - if raw[pos+1] >= b'0' && raw[pos+1] <= b'9' { + failure::ensure!( + pos + 1 < raw.len(), + "unexpected end of name after backslash: {:?}", + value + ); + if raw[pos + 1] >= b'0' && raw[pos + 1] <= b'9' { // \ddd escape - failure::ensure!(pos + 3 < raw.len(), "unexpected end of name after backslash with digit: {:?}", value); - failure::ensure!(raw[pos+2] >= b'0' && raw[pos+2] <= b'9' && raw[pos+3] >= b'0' && raw[pos+3] <= b'9', "expected three digits after backslash in name: {:?}", name); - let d1 = (raw[pos+1] - b'0') as u32; - let d2 = (raw[pos+2] - b'0') as u32; - let d3 = (raw[pos+3] - b'0') as u32; + failure::ensure!( + pos + 3 < raw.len(), + "unexpected end of name after backslash with digit: {:?}", + value + ); + failure::ensure!( + raw[pos + 2] >= b'0' + && raw[pos + 2] <= b'9' && raw[pos + 3] >= b'0' + && raw[pos + 3] <= b'9', + "expected three digits after backslash in name: {:?}", + name + ); + let d1 = (raw[pos + 1] - b'0') as u32; + let d2 = (raw[pos + 2] - b'0') as u32; + let d3 = (raw[pos + 3] - b'0') as u32; let v = d1 * 100 + d2 * 10 + d3; failure::ensure!(v < 256, "invalid escape in name, {} > 255: {:?}", v, name); label.push(v as u8); } else { failure::ensure!(!quoted::is_ascii_whitespace(raw[pos+1]), "whitespace cannot be escaped with backslash prefix; encode it as \\{:03} in: {:?}", raw[pos+1], name); - label.push(raw[pos+1]); + label.push(raw[pos + 1]); } } else { - failure::ensure!(!quoted::is_ascii_whitespace(raw[pos]), "whitespace must be encoded as \\{:03} in: {:?}", raw[pos], name); + failure::ensure!( + !quoted::is_ascii_whitespace(raw[pos]), + "whitespace must be encoded as \\{:03} in: {:?}", + raw[pos], + name + ); label.push(raw[pos]); } pos += 1; @@ -55,7 +73,9 @@ pub fn parse_name(context: &DnsTextContext, value: &str) -> Result match context.origin() { Some(o) => { - for l in o { name.push_back(l)?; } + for l in o { + name.push_back(l)?; + } }, None => failure::bail!("missing trailing dot without $ORIGIN"), } diff --git a/lib/dnsbox-base/src/common_types/name/tests.rs b/lib/dnsbox-base/src/common_types/name/tests.rs index 47961ab..7e9c2a7 100644 --- a/lib/dnsbox-base/src/common_types/name/tests.rs +++ b/lib/dnsbox-base/src/common_types/name/tests.rs @@ -1,10 +1,10 @@ -use bytes::Bytes; +use crate::errors::*; use crate::ser::packet; use crate::ser::packet::DnsPacketData; +use bytes::Bytes; use std::io::Cursor; -use crate::errors::*; -use super::{DnsName, DnsCompressedName, DnsLabelRef, DisplayLabels, DisplayLabelsOptions}; +use super::{DisplayLabels, DisplayLabelsOptions, DnsCompressedName, DnsLabelRef, DnsName}; /* fn deserialize(bytes: &'static [u8]) -> Result { @@ -25,40 +25,20 @@ fn de_uncompressed(bytes: &'static [u8]) -> Result { fn check_uncompressed_display(bytes: &'static [u8], txt: &str, label_count: u8) { let name = de_uncompressed(bytes).unwrap(); - assert_eq!( - name.labels().count(), - label_count as usize - ); - assert_eq!( - format!("{}", name), - txt - ); + assert_eq!(name.labels().count(), label_count as usize); + assert_eq!(format!("{}", name), txt); } fn check_uncompressed_debug(bytes: &'static [u8], txt: &str) { let name = de_uncompressed(bytes).unwrap(); - assert_eq!( - format!("{:?}", name), - txt - ); + assert_eq!(format!("{:?}", name), txt); } #[test] fn parse_and_display_name() { - check_uncompressed_display( - b"\x07example\x03com\x00", - "example.com.", - 2, - ); - check_uncompressed_display( - b"\x07e!am.l\\\x03com\x00", - "e\\033am\\.l\\\\.com.", - 2, - ); - check_uncompressed_debug( - b"\x07e!am.l\\\x03com\x00", - r#""e\\033am\\.l\\\\.com.""#, - ); + check_uncompressed_display(b"\x07example\x03com\x00", "example.com.", 2); + check_uncompressed_display(b"\x07e!am.l\\\x03com\x00", "e\\033am\\.l\\\\.com.", 2); + check_uncompressed_debug(b"\x07e!am.l\\\x03com\x00", r#""e\\033am\\.l\\\\.com.""#); } #[test] @@ -67,9 +47,9 @@ fn parse_and_reverse_name() { assert_eq!( format!( "{}", - DisplayLabels{ + DisplayLabels { labels: name.labels().rev(), - options: DisplayLabelsOptions{ + options: DisplayLabelsOptions { separator: " ", trailing: false, }, @@ -84,41 +64,24 @@ fn modifications() { let mut name = de_uncompressed(b"\x07example\x03com\x00").unwrap(); name.push_front(DnsLabelRef::new(b"www").unwrap()).unwrap(); - assert_eq!( - format!("{}", name), - "www.example.com." - ); + assert_eq!(format!("{}", name), "www.example.com."); name.push_back(DnsLabelRef::new(b"org").unwrap()).unwrap(); - assert_eq!( - format!("{}", name), - "www.example.com.org." - ); + assert_eq!(format!("{}", name), "www.example.com.org."); name.pop_front(); - assert_eq!( - format!("{}", name), - "example.com.org." - ); + assert_eq!(format!("{}", name), "example.com.org."); name.push_front(DnsLabelRef::new(b"mx").unwrap()).unwrap(); - assert_eq!( - format!("{}", name), - "mx.example.com.org." - ); + assert_eq!(format!("{}", name), "mx.example.com.org."); // the "mx" label should fit into the place "www" used before, // make sure the buffer was reused and the name not moved within assert_eq!(1, name.label_offsets.label_pos(0)); name.push_back(DnsLabelRef::new(b"com").unwrap()).unwrap(); - assert_eq!( - format!("{}", name), - "mx.example.com.org.com." - ); + assert_eq!(format!("{}", name), "mx.example.com.org.com."); } - - fn de_compressed(bytes: &'static [u8], offset: usize) -> Result { use bytes::Buf; @@ -133,22 +96,13 @@ fn de_compressed(bytes: &'static [u8], offset: usize) -> Result prev_window, "wrong nsec bitmap window order, {:?} <= {:?}", Some(window_base), prev_window); + failure::ensure!( + Some(window_base) > prev_window, + "wrong nsec bitmap window order, {:?} <= {:?}", + Some(window_base), + prev_window + ); prev_window = Some(window_base); check_enough_data!(data, 1, "nsec bitmap window length"); let window_len = data.get_u8() as u16; @@ -89,16 +98,13 @@ impl DnsPacketData for NsecTypeBitmap { let mut v = data.get_u8(); for j in 0..8 { if 0 != v & 0x80 { - set.insert(Type(window_base + i*8 + j)); + set.insert(Type(window_base + i * 8 + j)); } v <<= 1; } } } - Ok(NsecTypeBitmap{ - raw: raw, - set: set, - }) + Ok(NsecTypeBitmap { raw: raw, set: set }) } fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { @@ -150,15 +156,21 @@ impl DnsPacketData for NextHashedOwnerName { impl DnsTextData for NextHashedOwnerName { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> crate::errors::Result { let field = next_field(data)?; - let raw = BASE32HEX_NOPAD_ALLOW_WS.decode(field.as_bytes()) + let raw = BASE32HEX_NOPAD_ALLOW_WS + .decode(field.as_bytes()) .with_context(|e| e.context(format!("invalid base32hex (no padding): {:?}", field)))?; failure::ensure!(raw.len() > 0, "NextHashedOwnerName must not be empty"); - failure::ensure!(raw.len() < 256, "NextHashedOwnerName field must be at most 255 bytes long"); + failure::ensure!( + raw.len() < 256, + "NextHashedOwnerName field must be at most 255 bytes long" + ); Ok(NextHashedOwnerName(raw.into())) } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { - if self.0.is_empty() { return Err(fmt::Error); } + if self.0.is_empty() { + return Err(fmt::Error); + } write!(f, "{}", BASE32HEX_NOPAD_ALLOW_WS.encode(&self.0)) } } diff --git a/lib/dnsbox-base/src/common_types/nxt.rs b/lib/dnsbox-base/src/common_types/nxt.rs index 3994350..6df5cbf 100644 --- a/lib/dnsbox-base/src/common_types/nxt.rs +++ b/lib/dnsbox-base/src/common_types/nxt.rs @@ -1,8 +1,8 @@ -use bytes::{Bytes, Buf, BufMut}; use crate::common_types::Type; use crate::errors::*; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, skip_whitespace}; +use crate::ser::packet::{remaining_bytes, DnsPacketData, DnsPacketWriteContext}; +use crate::ser::text::{skip_whitespace, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::{Buf, BufMut, Bytes}; use std::collections::BTreeSet; use std::fmt; use std::io::Cursor; @@ -67,10 +67,7 @@ impl DnsPacketData for NxtTypeBitmap { current += 1; } } - Ok(NxtTypeBitmap{ - raw: raw, - set: set, - }) + Ok(NxtTypeBitmap { raw: raw, set: set }) } fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { diff --git a/lib/dnsbox-base/src/common_types/sig.rs b/lib/dnsbox-base/src/common_types/sig.rs index 3e06629..4bc4b2a 100644 --- a/lib/dnsbox-base/src/common_types/sig.rs +++ b/lib/dnsbox-base/src/common_types/sig.rs @@ -1,8 +1,8 @@ -use bytes::Bytes; use crate::errors::*; -use failure::Fail; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; +use crate::ser::text::{next_field, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; +use failure::Fail; use std::fmt; use std::io::Cursor; @@ -38,11 +38,9 @@ impl DnsTextData for OptionalTTL { *data = data_found; Ok(OptionalTTL(ttl)) }, - Err(e) => { - Ok(OptionalTTL(context.last_ttl() - .ok_or_else(|| e.context("TTL not available in context, failed parsing optional TTL"))? - )) - }, + Err(e) => Ok(OptionalTTL(context.last_ttl().ok_or_else(|| { + e.context("TTL not available in context, failed parsing optional TTL") + })?)), } } diff --git a/lib/dnsbox-base/src/common_types/text.rs b/lib/dnsbox-base/src/common_types/text.rs index 867964d..aa16911 100644 --- a/lib/dnsbox-base/src/common_types/text.rs +++ b/lib/dnsbox-base/src/common_types/text.rs @@ -1,7 +1,9 @@ -use bytes::{Bytes, Buf, BufMut}; use crate::errors::*; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, short_blob, write_short_blob, remaining_bytes}; +use crate::ser::packet::{ + remaining_bytes, short_blob, write_short_blob, DnsPacketData, DnsPacketWriteContext, +}; use crate::ser::text::*; +use bytes::{Buf, BufMut, Bytes}; use std::fmt; use std::io::Cursor; @@ -43,7 +45,9 @@ impl DnsPacketData for LongText { let mut texts = Vec::new(); loop { texts.push(short_blob(data)?); - if !data.has_remaining() { break; } + if !data.has_remaining() { + break; + } } Ok(LongText(texts)) } @@ -66,7 +70,10 @@ impl DnsTextData for LongText { skip_whitespace(data); while !data.is_empty() { let part = next_quoted_field(data)?; - failure::ensure!(part.len() < 256, "long text component must be at most 255 bytes long"); + failure::ensure!( + part.len() < 256, + "long text component must be at most 255 bytes long" + ); result.push(part.into()); } Ok(LongText(result)) diff --git a/lib/dnsbox-base/src/common_types/time/epoch.rs b/lib/dnsbox-base/src/common_types/time/epoch.rs index a3a9e5e..2830366 100644 --- a/lib/dnsbox-base/src/common_types/time/epoch.rs +++ b/lib/dnsbox-base/src/common_types/time/epoch.rs @@ -36,7 +36,11 @@ fn test_is_leap_year() { fn month_day_of_year_since_march(month: u8) -> u16 { debug_assert!(month >= 1 && month <= 12); - let month_from_march = if month > 2 { month as u16 - 3} else { month as u16 + 9 }; + let month_from_march = if month > 2 { + month as u16 - 3 + } else { + month as u16 + 9 + }; (153 * month_from_march + 2) / 5 } @@ -49,7 +53,11 @@ fn month_and_day_from_day_of_year_since_march(day_of_year: i32) -> (u8, u8) { let month_from_march = month_from_march as u8; - let month = if month_from_march < 10 { month_from_march + 3 } else { month_from_march - 9 }; + let month = if month_from_march < 10 { + month_from_march + 3 + } else { + month_from_march - 9 + }; debug_assert!(month >= 1 && month <= 12); (month, day as u8) @@ -57,12 +65,18 @@ fn month_and_day_from_day_of_year_since_march(day_of_year: i32) -> (u8, u8) { #[test] fn test_month_day_of_year_since_march() { - static MONTH_START: [u16; 12] = [306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, ]; + static MONTH_START: [u16; 12] = [306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275]; static DAYS_IN_MONTHS: [u8; 12] = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; for (m, &s) in MONTH_START.iter().enumerate() { assert_eq!(month_day_of_year_since_march(m as u8 + 1), s); - assert_eq!(month_and_day_from_day_of_year_since_march(s as i32), (m as u8 + 1, 1)); - assert_eq!(month_and_day_from_day_of_year_since_march(s as i32 + DAYS_IN_MONTHS[m] as i32 - 1), (m as u8 + 1, DAYS_IN_MONTHS[m])); + assert_eq!( + month_and_day_from_day_of_year_since_march(s as i32), + (m as u8 + 1, 1) + ); + assert_eq!( + month_and_day_from_day_of_year_since_march(s as i32 + DAYS_IN_MONTHS[m] as i32 - 1), + (m as u8 + 1, DAYS_IN_MONTHS[m]) + ); } assert_eq!(month_and_day_from_day_of_year_since_march(365), (2, 29)); } @@ -136,7 +150,7 @@ fn split_days_since_march1_y0_into_era(days: i32) -> (i32, i32) { } fn year_of_era_from_day_of_era(day_of_era: i32) -> i32 { - let res = (day_of_era - day_of_era/1460 + day_of_era/36524 - day_of_era/146096) / 365; + let res = (day_of_era - day_of_era / 1460 + day_of_era / 36524 - day_of_era / 146096) / 365; debug_assert!(res >= 0 && res <= 399); res } @@ -197,23 +211,29 @@ fn test_days_since_march1_y0() { assert_eq!(days_since_march1_y0(0, 3, 1), 0); assert_eq!(days_since_march1_y0(1, 3, 1), 365); assert_eq!(days_since_march1_y0(1970, 1, 1), EPOCH_DAYS_SINCE_MARCH1_Y0); - assert_eq!(days_since_march1_y0(1970, 1, 1), - /* regular days in years: */ 365 * 1969 + assert_eq!( + days_since_march1_y0(1970, 1, 1), + /* regular days in years: */ + 365 * 1969 /* days from leap years: */ + (1969 / 4 - 15) - /* days from march 1st year 0 to january 1st year 1: */ + 306); + /* days from march 1st year 0 to january 1st year 1: */ + 306 + ); assert_eq!(split_days_since_march1_y0(-366), (-1, 3, 1)); assert_eq!(split_days_since_march1_y0(0), (0, 3, 1)); assert_eq!(split_days_since_march1_y0(365), (1, 3, 1)); - assert_eq!(split_days_since_march1_y0(EPOCH_DAYS_SINCE_MARCH1_Y0), (1970, 1, 1)); + assert_eq!( + split_days_since_march1_y0(EPOCH_DAYS_SINCE_MARCH1_Y0), + (1970, 1, 1) + ); } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Tm { - pub year: i16, // absolute year: 1 is "1 AD", 0 is "1 BC". - pub month: u8, // 01...12 - pub day: u8, // 01..31 - pub hour: u8, // 00..23 + pub year: i16, // absolute year: 1 is "1 AD", 0 is "1 BC". + pub month: u8, // 01...12 + pub day: u8, // 01..31 + pub hour: u8, // 00..23 pub minute: u8, // 00..59 pub second: u8, // 00..59 } @@ -223,7 +243,10 @@ impl Tm { pub fn from_epoch(epoch: i64) -> Result { let (day, time_of_day) = pos_div_rem64(epoch, 86400); let days_since_march1_y0 = day + EPOCH_DAYS_SINCE_MARCH1_Y0 as i64; - failure::ensure!((days_since_march1_y0 as i32) as i64 == days_since_march1_y0, "days in epoch out of range"); + failure::ensure!( + (days_since_march1_y0 as i32) as i64 == days_since_march1_y0, + "days in epoch out of range" + ); let days_since_march1_y0 = days_since_march1_y0 as i32; let (year, month, day) = split_days_since_march1_y0(days_since_march1_y0); @@ -233,7 +256,7 @@ impl Tm { let (minute_of_day, second) = pos_div_rem(time_of_day as i32, 60); let (hour, minute) = pos_div_rem(minute_of_day, 60); - Ok(Tm{ + Ok(Tm { year, month, day, @@ -249,9 +272,7 @@ impl Tm { } fn day_seconds(&self) -> u32 { - self.second as u32 - + 60 * self.minute as u32 - + 3600 * self.hour as u32 + self.second as u32 + 60 * self.minute as u32 + 3600 * self.hour as u32 } pub fn epoch(&self) -> i64 { @@ -261,44 +282,73 @@ impl Tm { #[allow(non_snake_case)] pub fn parse_YYYYMMDDHHmmSS(s: &str) -> Result { failure::ensure!(s.len() == 14, "Tm string must be exactly 14 digits long"); - failure::ensure!(s.as_bytes().iter().all(|&b| b >= b'0' && b <= b'9'), "Tm string must be exactly 14 digits long"); + failure::ensure!( + s.as_bytes().iter().all(|&b| b >= b'0' && b <= b'9'), + "Tm string must be exactly 14 digits long" + ); let year = s[0..4].parse::()?; failure::ensure!(year >= 1, "year must be >= 1"); failure::ensure!(year <= 9999, "year must be <= 9999"); fn p(s: &str, min: u8, max: u8, name: &'static str) -> crate::errors::Result { let v = s.parse::()?; - failure::ensure!(v >= min && v <= max, "{} {} out of range {}-{}", name, v, min, max); + failure::ensure!( + v >= min && v <= max, + "{} {} out of range {}-{}", + name, + v, + min, + max + ); Ok(v) } - let month = p(&s[4..6], 1, 12, "month")?; - let day = p(&s[6..8], 1, 31, "day")?; - let hour = p(&s[8..10], 0, 23, "hour")?; + let month = p(&s[4..6], 1, 12, "month")?; + let day = p(&s[6..8], 1, 31, "day")?; + let hour = p(&s[8..10], 0, 23, "hour")?; let minute = p(&s[10..12], 0, 59, "minute")?; let second = p(&s[12..14], 0, 59, "second")?; if 2 == month { failure::ensure!(day < 30, "day {} out of range in february", day); - failure::ensure!(is_leap_year(year) || day < 29, "day {} out of range in february (not a leap year)", day); + failure::ensure!( + is_leap_year(year) || day < 29, + "day {} out of range in february (not a leap year)", + day + ); } else { static DAYS_IN_MONTHS: [u8; 12] = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; let max_days = DAYS_IN_MONTHS[month as usize - 1]; - failure::ensure!(day <= max_days, "day {} out of range for month {}", day, month); + failure::ensure!( + day <= max_days, + "day {} out of range for month {}", + day, + month + ); } - Ok(Tm{ year, month, day, hour, minute, second }) + Ok(Tm { + year, + month, + day, + hour, + minute, + second, + }) } #[allow(non_snake_case)] pub fn format_YYYYMMDDHHmmSS(&self, f: &mut W) -> fmt::Result where - W: fmt::Write + ?Sized + W: fmt::Write + ?Sized, { - if self.year < 0 || self.year > 9999 { return Err(fmt::Error); } - write!(f, "{:04}{:02}{:02}{:02}{:02}{:02}", - self.year, self.month, self.day, - self.hour, self.minute, self.second + if self.year < 0 || self.year > 9999 { + return Err(fmt::Error); + } + write!( + f, + "{:04}{:02}{:02}{:02}{:02}{:02}", + self.year, self.month, self.day, self.hour, self.minute, self.second ) } } diff --git a/lib/dnsbox-base/src/common_types/time/mod.rs b/lib/dnsbox-base/src/common_types/time/mod.rs index d449e8a..70a1605 100644 --- a/lib/dnsbox-base/src/common_types/time/mod.rs +++ b/lib/dnsbox-base/src/common_types/time/mod.rs @@ -1,7 +1,7 @@ -use bytes::Bytes; use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; +use crate::ser::text::{next_field, DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; use std::fmt; use std::io::Cursor; @@ -39,7 +39,9 @@ impl DnsTextData for Time { } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { - epoch::Tm::from_epoch(self.0 as i64).unwrap().format_YYYYMMDDHHmmSS(&mut*f.format_field()?) + epoch::Tm::from_epoch(self.0 as i64) + .unwrap() + .format_YYYYMMDDHHmmSS(&mut *f.format_field()?) } } @@ -69,7 +71,9 @@ impl DnsTextData for TimeStrict { } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { - epoch::Tm::from_epoch(self.0 as i64).unwrap().format_YYYYMMDDHHmmSS(&mut*f.format_field()?) + epoch::Tm::from_epoch(self.0 as i64) + .unwrap() + .format_YYYYMMDDHHmmSS(&mut *f.format_field()?) } } diff --git a/lib/dnsbox-base/src/common_types/uri.rs b/lib/dnsbox-base/src/common_types/uri.rs index 4e93572..4e3ba2f 100644 --- a/lib/dnsbox-base/src/common_types/uri.rs +++ b/lib/dnsbox-base/src/common_types/uri.rs @@ -1,7 +1,7 @@ -use bytes::{Bytes, BufMut}; use crate::errors::*; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes}; +use crate::ser::packet::{remaining_bytes, DnsPacketData, DnsPacketWriteContext}; use crate::ser::text::*; +use bytes::{BufMut, Bytes}; use std::fmt; use std::io::Cursor; diff --git a/lib/dnsbox-base/src/crypto/pubkey.rs b/lib/dnsbox-base/src/crypto/pubkey.rs index 740f888..4ee89b0 100644 --- a/lib/dnsbox-base/src/crypto/pubkey.rs +++ b/lib/dnsbox-base/src/crypto/pubkey.rs @@ -14,10 +14,16 @@ fn parse_rsa(data: &[u8]) -> crate::errors::Result { let exp_len: usize; let offset: usize; if data[0] == 0 { - failure::ensure!(data.len() >= 3, "RSA public key: unexpected end of data when decoding exponent length"); + failure::ensure!( + data.len() >= 3, + "RSA public key: unexpected end of data when decoding exponent length" + ); exp_len = (data[1] as usize) << 8 + (data[2] as usize); offset = 3; - failure::ensure!(exp_len >= 256, "RSA public key: exponent length in long form but too small"); + failure::ensure!( + exp_len >= 256, + "RSA public key: exponent length in long form but too small" + ); } else { exp_len = data[0] as usize; offset = 1; @@ -25,23 +31,37 @@ fn parse_rsa(data: &[u8]) -> crate::errors::Result { assert!(exp_len > 0); // should be unreachable: 0 means two bytes, which are checked for >= 256 - failure::ensure!(exp_len <= RSA_BYTES_LIMIT, "RSA public key: exponent too long (limit: {} bits)", RSA_BITS_LIMIT); + failure::ensure!( + exp_len <= RSA_BYTES_LIMIT, + "RSA public key: exponent too long (limit: {} bits)", + RSA_BITS_LIMIT + ); - failure::ensure!(data.len() >= offset + exp_len, "RSA public key: unexpected end of data when reading exponent"); - failure::ensure!(data[offset] != 0, "RSA public key: leading zero in exponent"); + failure::ensure!( + data.len() >= offset + exp_len, + "RSA public key: unexpected end of data when reading exponent" + ); + failure::ensure!( + data[offset] != 0, + "RSA public key: leading zero in exponent" + ); let exponent = BigUint::from_bytes_be(&data[offset..][..exp_len]); let modulus_data = &data[offset..][exp_len..]; - failure::ensure!(modulus_data.len() <= RSA_BYTES_LIMIT, "RSA public key: modulus too long (limit: {} bits)", RSA_BITS_LIMIT); + failure::ensure!( + modulus_data.len() <= RSA_BYTES_LIMIT, + "RSA public key: modulus too long (limit: {} bits)", + RSA_BITS_LIMIT + ); failure::ensure!(!modulus_data.is_empty(), "RSA public key: modulus empty"); - failure::ensure!(modulus_data[offset] != 0, "RSA public key: leading zero in modulus"); + failure::ensure!( + modulus_data[offset] != 0, + "RSA public key: leading zero in modulus" + ); let modulus = BigUint::from_bytes_be(modulus_data); - Ok(PublicKey::RSA { - exponent, - modulus, - }) + Ok(PublicKey::RSA { exponent, modulus }) } #[allow(non_camel_case_types)] @@ -58,34 +78,53 @@ impl PublicKey { pub fn parse(algorithm: DnsSecAlgorithm, data: &[u8]) -> crate::errors::Result { use DnsSecAlgorithmKnown::*; - let algorithm = algorithm.into_known().ok_or_else(|| failure::format_err!("Unknown algorithm"))?; + let algorithm = algorithm + .into_known() + .ok_or_else(|| failure::format_err!("Unknown algorithm"))?; match algorithm { - DELETE|INDIRECT|PRIVATEDNS|PRIVATEOID => failure::bail!("Algorithm {:?} not used with actual key", algorithm), - RSAMD5|RSASHA1|RSASHA1_NSEC3_SHA1|RSASHA256|RSASHA512 => parse_rsa(data), - DH|DSA|DSA_NSEC3_SHA1 => failure::bail!("Algorithm {:?} not supported", algorithm), + DELETE | INDIRECT | PRIVATEDNS | PRIVATEOID => { + failure::bail!("Algorithm {:?} not used with actual key", algorithm) + }, + RSAMD5 | RSASHA1 | RSASHA1_NSEC3_SHA1 | RSASHA256 | RSASHA512 => parse_rsa(data), + DH | DSA | DSA_NSEC3_SHA1 => failure::bail!("Algorithm {:?} not supported", algorithm), ECDSAP256SHA256 => { - failure::ensure!(data.len() == 64, "Expected 64 bytes public key for ECDSAP256"); + failure::ensure!( + data.len() == 64, + "Expected 64 bytes public key for ECDSAP256" + ); let mut x = [0u8; 32]; x.copy_from_slice(&data[..32]); let mut y = [0u8; 32]; y.copy_from_slice(&data[32..]); - Ok(PublicKey::ECDSAP256 { xy: Box::new((x, y)) }) + Ok(PublicKey::ECDSAP256 { + xy: Box::new((x, y)), + }) }, ECDSAP384SHA384 => { - failure::ensure!(data.len() == 96, "Expected 96 bytes public key for ECDSAP384"); + failure::ensure!( + data.len() == 96, + "Expected 96 bytes public key for ECDSAP384" + ); let mut x = [0u8; 48]; x.copy_from_slice(&data[..48]); let mut y = [0u8; 48]; y.copy_from_slice(&data[48..]); - Ok(PublicKey::ECDSAP384 { xy: Box::new((x, y)) }) + Ok(PublicKey::ECDSAP384 { + xy: Box::new((x, y)), + }) }, ECC_GOST => { - failure::ensure!(data.len() == 64, "Expected 64 bytes public key for ECC_GOST"); + failure::ensure!( + data.len() == 64, + "Expected 64 bytes public key for ECC_GOST" + ); let mut x = [0u8; 32]; x.copy_from_slice(&data[..32]); let mut y = [0u8; 32]; y.copy_from_slice(&data[32..]); - Ok(PublicKey::ECC_GOST { xy: Box::new((x, y)) }) + Ok(PublicKey::ECC_GOST { + xy: Box::new((x, y)), + }) }, ED25519 => { failure::ensure!(data.len() == 32, "Expected 32 bytes public key for ED25519"); @@ -105,11 +144,11 @@ impl PublicKey { pub fn bits(&self) -> Option { match self { PublicKey::RSA { modulus, .. } => Some(modulus.bits() as u32), - PublicKey::ECDSAP256 { .. } => Some(32*8), - PublicKey::ECDSAP384 { .. } => Some(48*8), - PublicKey::ECC_GOST { .. } => Some(32*8), - PublicKey::ED25519 { .. } => Some(32*8), - PublicKey::ED448 { .. } => Some(57*8), + PublicKey::ECDSAP256 { .. } => Some(32 * 8), + PublicKey::ECDSAP384 { .. } => Some(48 * 8), + PublicKey::ECC_GOST { .. } => Some(32 * 8), + PublicKey::ED25519 { .. } => Some(32 * 8), + PublicKey::ED448 { .. } => Some(57 * 8), } } } diff --git a/lib/dnsbox-base/src/errors.rs b/lib/dnsbox-base/src/errors.rs index 04dfb81..1a0e47a 100644 --- a/lib/dnsbox-base/src/errors.rs +++ b/lib/dnsbox-base/src/errors.rs @@ -15,7 +15,7 @@ pub struct NotEnoughData { impl NotEnoughData { pub fn check(data: &mut io::Cursor, need: usize) -> Result<()> { if data.remaining() < need { - failure::bail!(NotEnoughData{ + failure::bail!(NotEnoughData { position: data.position(), data: data.get_ref().clone(), }) @@ -26,17 +26,19 @@ impl NotEnoughData { impl fmt::Display for NotEnoughData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "not enough data at position {} in {:?}", self.position, self.data) + write!( + f, + "not enough data at position {} in {:?}", + self.position, self.data + ) } } impl failure::Fail for NotEnoughData {} macro_rules! check_enough_data { - ($data:ident, $n:expr, $context:expr) => { - { - use $crate::_failure::ResultExt; - $crate::errors::NotEnoughData::check($data, $n).context($context)?; - } - }; + ($data:ident, $n:expr, $context:expr) => {{ + use $crate::_failure::ResultExt; + $crate::errors::NotEnoughData::check($data, $n).context($context)?; + }}; } diff --git a/lib/dnsbox-base/src/lib.rs b/lib/dnsbox-base/src/lib.rs index 57c8c46..0cfe094 100644 --- a/lib/dnsbox-base/src/lib.rs +++ b/lib/dnsbox-base/src/lib.rs @@ -1,17 +1,17 @@ #[doc(hidden)] -pub use failure as _failure; // re-export for macros +pub use bytes as _bytes; #[doc(hidden)] -pub use bytes as _bytes; // re-export for macros +pub use failure as _failure; // re-export for macros // re-export for macros extern crate self as dnsbox_base; #[macro_use] pub mod errors; +pub mod common_types; #[cfg(feature = "crypto")] pub mod crypto; -pub mod common_types; -pub mod ser; pub mod packet; pub mod records; +pub mod ser; mod unsafe_ops; diff --git a/lib/dnsbox-base/src/packet/mod.rs b/lib/dnsbox-base/src/packet/mod.rs index bbe50ad..e9ef5b0 100644 --- a/lib/dnsbox-base/src/packet/mod.rs +++ b/lib/dnsbox-base/src/packet/mod.rs @@ -1,11 +1,11 @@ -use byteorder::ByteOrder; -use bytes::{Bytes, Buf, BufMut, BigEndian}; -use crate::common_types::{Type, Class, DnsCompressedName, types}; +use crate::common_types::{types, Class, DnsCompressedName, Type}; use crate::errors::*; -use crate::ser::RRData; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use std::io::Cursor; use crate::records::registry::deserialize_rr_data; +use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; +use crate::ser::RRData; +use byteorder::ByteOrder; +use bytes::{BigEndian, Buf, BufMut, Bytes}; +use std::io::Cursor; pub mod opt; @@ -38,17 +38,21 @@ pub struct DnsHeaderFlags { impl DnsPacketData for DnsHeaderFlags { fn deserialize(data: &mut Cursor) -> Result { let raw = u16::deserialize(data)?; - let qr = if 0 == raw & 0x8000 { QueryResponse::Query } else { QueryResponse::Response }; + let qr = if 0 == raw & 0x8000 { + QueryResponse::Query + } else { + QueryResponse::Response + }; let opcode = 0xf & (raw >> 11) as u8; let authoritative_answer = 0 != raw & 0x0400; - let truncation = 0 != raw & 0x0200; - let recursion_desired = 0 != raw & 0x0100; - let recursion_available = 0 != raw & 0x0080; - let reserved_bit9 = 0 != raw & 0x0040; - let authentic_data = 0 != raw & 0x0020; - let checking_disabled = 0 != raw & 0x0010; + let truncation = 0 != raw & 0x0200; + let recursion_desired = 0 != raw & 0x0100; + let recursion_available = 0 != raw & 0x0080; + let reserved_bit9 = 0 != raw & 0x0040; + let authentic_data = 0 != raw & 0x0020; + let checking_disabled = 0 != raw & 0x0010; let rcode = 0xf & raw as u8; - Ok(DnsHeaderFlags{ + Ok(DnsHeaderFlags { qr, opcode, authoritative_answer, @@ -67,17 +71,15 @@ impl DnsPacketData for DnsHeaderFlags { | match self.qr { QueryResponse::Query => 0, QueryResponse::Response => 1, - } - | (((0xf & self.opcode) as u16) << 11) + } | (((0xf & self.opcode) as u16) << 11) | if self.authoritative_answer { 0x0400 } else { 0 } - | if self.truncation { 0x0200 } else { 0 } - | if self.recursion_desired { 0x0100 } else { 0 } - | if self.recursion_available { 0x0080 } else { 0 } - | if self.reserved_bit9 { 0x0040 } else { 0 } - | if self.authentic_data { 0x0020 } else { 0 } - | if self.checking_disabled { 0x0010 } else { 0 } - | (0xf & self.rcode) as u16 - ; + | if self.truncation { 0x0200 } else { 0 } + | if self.recursion_desired { 0x0100 } else { 0 } + | if self.recursion_available { 0x0080 } else { 0 } + | if self.reserved_bit9 { 0x0040 } else { 0 } + | if self.authentic_data { 0x0020 } else { 0 } + | if self.checking_disabled { 0x0010 } else { 0 } + | (0xf & self.rcode) as u16; flags.serialize(context, packet) } } @@ -123,9 +125,13 @@ impl DnsPacketData for Resource { rrdata.advance(pos); let rd = deserialize_rr_data(ttl, class, rr_type, &mut rrdata)?; - failure::ensure!(!rrdata.has_remaining(), "data remaining: {} bytes", rrdata.remaining()); + failure::ensure!( + !rrdata.has_remaining(), + "data remaining: {} bytes", + rrdata.remaining() + ); - Ok(Resource{ + Ok(Resource { name, class, ttl, @@ -204,7 +210,7 @@ impl DnsPacket { impl Default for DnsPacket { fn default() -> Self { - DnsPacket{ + DnsPacket { id: 0, flags: DnsHeaderFlags::default(), question: Vec::new(), @@ -222,10 +228,18 @@ impl DnsPacketData for DnsPacket { let mut p = DnsPacket { id: header.id, flags: header.flags, - question: (0..header.qdcount).map(|_| Question::deserialize(data)).collect::>>()?, - answer: (0..header.ancount).map(|_| Resource::deserialize(data)).collect::>>()?, - authority: (0..header.nscount).map(|_| Resource::deserialize(data)).collect::>>()?, - additional: (0..header.arcount).map(|_| Resource::deserialize(data)).collect::>>()?, + question: (0..header.qdcount) + .map(|_| Question::deserialize(data)) + .collect::>>()?, + answer: (0..header.ancount) + .map(|_| Resource::deserialize(data)) + .collect::>>()?, + authority: (0..header.nscount) + .map(|_| Resource::deserialize(data)) + .collect::>>()?, + additional: (0..header.arcount) + .map(|_| Resource::deserialize(data)) + .collect::>>()?, opt: None, }; @@ -249,9 +263,15 @@ impl DnsPacketData for DnsPacket { fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { failure::ensure!(self.question.len() < 0x1_0000, "too many question entries"); failure::ensure!(self.answer.len() < 0x1_0000, "too many answer entries"); - failure::ensure!(self.authority.len() < 0x1_0000, "too many authority entries"); - failure::ensure!(self.additional.len() < 0x1_0000, "too many additional entries"); - let header = DnsHeader{ + failure::ensure!( + self.authority.len() < 0x1_0000, + "too many authority entries" + ); + failure::ensure!( + self.additional.len() < 0x1_0000, + "too many additional entries" + ); + let header = DnsHeader { id: self.id, flags: self.flags, qdcount: self.question.len() as u16, diff --git a/lib/dnsbox-base/src/packet/opt.rs b/lib/dnsbox-base/src/packet/opt.rs index 1c634ca..9c474b4 100644 --- a/lib/dnsbox-base/src/packet/opt.rs +++ b/lib/dnsbox-base/src/packet/opt.rs @@ -1,10 +1,10 @@ -use byteorder::ByteOrder; -use bytes::{Bytes, Buf, BufMut, BigEndian}; -use crate::common_types::{DnsCompressedName, Class, types}; +use crate::common_types::{types, Class, DnsCompressedName}; use crate::errors::*; use crate::packet::Resource; use crate::records::UnknownRecord; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, get_blob, remaining_bytes}; +use crate::ser::packet::{get_blob, remaining_bytes, DnsPacketData, DnsPacketWriteContext}; +use byteorder::ByteOrder; +use bytes::{BigEndian, Buf, BufMut, Bytes}; use std::io::{Cursor, Read}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -65,7 +65,7 @@ pub enum DnsOption { Unknown { code: u16, data: Bytes, - } + }, } impl DnsOption { @@ -74,7 +74,12 @@ impl DnsOption { let source_prefix_length = u8::deserialize(data)?; let scope_prefix_length = u8::deserialize(data)?; let addr_prefix_len = ((source_prefix_length + 7) / 8) as usize; - failure::ensure!(scope_prefix_length <= source_prefix_length, "scope prefix {} > source prefix {}", scope_prefix_length, source_prefix_length); + failure::ensure!( + scope_prefix_length <= source_prefix_length, + "scope prefix {} > source prefix {}", + scope_prefix_length, + source_prefix_length + ); let addr = match addr_family { 1 => { failure::ensure!(source_prefix_length <= 32, "invalid prefix for IPv4"); @@ -100,7 +105,7 @@ impl DnsOption { failure::bail!("unknown address family {}", addr_family); }, }; - Ok(DnsOption::ClientSubnet{ + Ok(DnsOption::ClientSubnet { source_prefix_length, scope_prefix_length, addr, @@ -110,24 +115,38 @@ impl DnsOption { fn parse_opt(code: u16, opt_data: Bytes) -> Result { let mut data = Cursor::new(opt_data); - let result = (|| Ok(match code { - 0x0003 => DnsOption::NSID(remaining_bytes(&mut data)), - 0x0008 => DnsOption::parse_client_subnet(&mut data)?, - _ => failure::bail!("unknown option {}", code), - }))()?; + let result = (|| { + Ok(match code { + 0x0003 => DnsOption::NSID(remaining_bytes(&mut data)), + 0x0008 => DnsOption::parse_client_subnet(&mut data)?, + _ => failure::bail!("unknown option {}", code), + }) + })()?; - failure::ensure!(!data.has_remaining(), "option data remaining: {} bytes", data.remaining()); + failure::ensure!( + !data.has_remaining(), + "option data remaining: {} bytes", + data.remaining() + ); Ok(result) } - fn write_opt_data(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { + fn write_opt_data( + &self, + _context: &mut DnsPacketWriteContext, + packet: &mut Vec, + ) -> Result<()> { match *self { DnsOption::NSID(ref id) => { packet.reserve(id.len()); packet.put_slice(id); }, - DnsOption::ClientSubnet{source_prefix_length, scope_prefix_length, ref addr} => { + DnsOption::ClientSubnet { + source_prefix_length, + scope_prefix_length, + ref addr, + } => { let addr_prefix_len = ((source_prefix_length + 7) / 8) as usize; packet.reserve(4 + addr_prefix_len); packet.put_u16_be(match *addr { @@ -148,7 +167,7 @@ impl DnsOption { }, } }, - DnsOption::Unknown{ref data, ..} => { + DnsOption::Unknown { ref data, .. } => { packet.reserve(data.len()); packet.put_slice(data); }, @@ -165,7 +184,7 @@ impl DnsPacketData for DnsOption { let opt_data = get_blob(data, opt_len)?; DnsOption::parse_opt(code, opt_data.clone()).or_else(|_| { - Ok(DnsOption::Unknown{ + Ok(DnsOption::Unknown { code: code, data: opt_data, }) @@ -175,8 +194,8 @@ impl DnsPacketData for DnsOption { fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { let code: u16 = match *self { DnsOption::NSID(_) => 0x0003, - DnsOption::ClientSubnet{..} => 0x0008, - DnsOption::Unknown{code, ..} => code, + DnsOption::ClientSubnet { .. } => 0x0008, + DnsOption::Unknown { code, .. } => code, }; code.serialize(context, packet)?; @@ -230,7 +249,9 @@ impl Opt { let version = (r.ttl >> 16) as u8; let flags = OptFlags(r.ttl as u16); - if version > 0 { return Ok(Err(OptError::UnknownVersion)); } + if version > 0 { + return Ok(Err(OptError::UnknownVersion)); + } let ur = match r.data.as_any().downcast_ref::() { Some(ur) => ur, @@ -263,7 +284,7 @@ impl Opt { let ttl = ((self.extended_rcode_high as u32) << 24) | ((self.version as u32) << 16) | self.flags.0 as u32; - Ok(Resource{ + Ok(Resource { name: DnsCompressedName::new_root(), class: Class(self.udp_payload_size), ttl: ttl, diff --git a/lib/dnsbox-base/src/records/mod.rs b/lib/dnsbox-base/src/records/mod.rs index fc70eda..b863189 100644 --- a/lib/dnsbox-base/src/records/mod.rs +++ b/lib/dnsbox-base/src/records/mod.rs @@ -1,7 +1,7 @@ -mod weird_structs; +pub mod registry; mod structs; mod unknown; -pub mod registry; +mod weird_structs; pub use self::structs::*; pub use self::unknown::*; diff --git a/lib/dnsbox-base/src/records/powerdns_tests.rs b/lib/dnsbox-base/src/records/powerdns_tests.rs index cb355bb..5e0f0a4 100644 --- a/lib/dnsbox-base/src/records/powerdns_tests.rs +++ b/lib/dnsbox-base/src/records/powerdns_tests.rs @@ -1,33 +1,29 @@ #![allow(non_snake_case)] -use bytes::Bytes; -use crate::common_types::{DnsName, DnsCompressedName, Class, Type, types, classes}; +use crate::common_types::{classes, types, Class, DnsCompressedName, DnsName, Type}; use crate::errors::*; +use crate::packet::opt::{DnsOption, Opt}; use crate::packet::*; -use crate::packet::opt::{Opt, DnsOption}; -use crate::records::{UnknownRecord, registry, A}; -use crate::ser::{RRData, text}; -use crate::ser::packet::{DnsPacketData, deserialize_with}; +use crate::records::{registry, UnknownRecord, A}; +use crate::ser::packet::{deserialize_with, DnsPacketData}; +use crate::ser::{text, RRData}; +use bytes::Bytes; use std::io::Cursor; fn fake_packet(rrtype: Type, raw: &[u8]) -> Bytes { - let mut p = DnsPacket{ - question: vec![ - Question { - qname: ".".parse().unwrap(), - qtype: rrtype, - qclass: classes::IN, - } - ], - answer: vec![ - Resource { - name: "rec.test.".parse().unwrap(), - class: classes::IN, - ttl: 0, - data: Box::new(UnknownRecord::new(rrtype, Bytes::from(raw))), - } - ], - .. Default::default() + let mut p = DnsPacket { + question: vec![Question { + qname: ".".parse().unwrap(), + qtype: rrtype, + qclass: classes::IN, + }], + answer: vec![Resource { + name: "rec.test.".parse().unwrap(), + class: classes::IN, + ttl: 0, + data: Box::new(UnknownRecord::new(rrtype, Bytes::from(raw))), + }], + ..Default::default() }; p.to_bytes().unwrap().into() @@ -56,29 +52,24 @@ fn get_first_answer_rdata(packet: Bytes) -> Result { } fn serialized_answer(rrdata: Box) -> Result { - let mut p = DnsPacket{ - question: vec![ - Question { - qname: ".".parse().unwrap(), - qtype: rrdata.rr_type(), - qclass: classes::IN, - } - ], - answer: vec![ - Resource { - name: "rec.test.".parse().unwrap(), - class: classes::IN, - ttl: 0, - data: rrdata, - } - ], - .. Default::default() + let mut p = DnsPacket { + question: vec![Question { + qname: ".".parse().unwrap(), + qtype: rrdata.rr_type(), + qclass: classes::IN, + }], + answer: vec![Resource { + name: "rec.test.".parse().unwrap(), + class: classes::IN, + ttl: 0, + data: rrdata, + }], + ..Default::default() }; get_first_answer_rdata(p.to_bytes()?.into()) } - fn check(q: Type, text_input: &'static str, canonic: Option<&'static str>, raw: &'static [u8]) { // Make sure the canonic representation is sound itself if let Some(canonic) = canonic { @@ -93,9 +84,8 @@ fn check(q: Type, text_input: &'static str, canonic: Option<&'static str>, raw: context.set_record_type(q); context.set_last_ttl(3600); - let d_zone: Box = text::parse_with(text_input, |data| { - registry::parse_rr_data(&context, data) - }).unwrap(); + let d_zone: Box = + text::parse_with(text_input, |data| registry::parse_rr_data(&context, data)).unwrap(); let d_zone_text = d_zone.text().unwrap(); // make sure we actually know the type and the text representation @@ -117,7 +107,10 @@ fn check(q: Type, text_input: &'static str, canonic: Option<&'static str>, raw: // pdns tests compare d_wire_text and canonic, but d_zone_text // already matches canonic - assert_eq!(d_zone_text, d_wire_text, "data parsed from zone doesn't match data from wire"); + assert_eq!( + d_zone_text, d_wire_text, + "data parsed from zone doesn't match data from wire" + ); let zone_as_wire = serialized_answer(d_zone).unwrap(); assert_eq!(zone_as_wire, raw); @@ -125,24 +118,16 @@ fn check(q: Type, text_input: &'static str, canonic: Option<&'static str>, raw: #[test] fn test_A() { - check(types::A, - "127.0.0.1", - None, - b"\x7F\x00\x00\x01", - ); + check(types::A, "127.0.0.1", None, b"\x7F\x00\x00\x01"); } - #[test] fn test_NS() { // local nameserver - check(types::NS, - "ns.rec.test.", - None, - b"\x02ns\xc0\x11", - ); + check(types::NS, "ns.rec.test.", None, b"\x02ns\xc0\x11"); // non-local nameserver - check(types::NS, + check( + types::NS, "ns.example.com.", None, b"\x02ns\x07example\x03com\x00", @@ -155,13 +140,10 @@ fn test_NS() { #[test] fn test_CNAME() { // local alias - check(types::CNAME, - "name.rec.test.", - None, - b"\x04name\xc0\x11", - ); + check(types::CNAME, "name.rec.test.", None, b"\x04name\xc0\x11"); // non-local alias - check(types::CNAME, + check( + types::CNAME, "name.example.com.", None, b"\x04name\x07example\x03com\x00", @@ -215,13 +197,15 @@ fn test_SOA() { fn test_MR() { // BROKEN TESTS (2) (deprecated) // local name - check(types::MR, + check( + types::MR, "newmailbox.rec.test.", None, b"\x0anewmailbox\xc0\x11", ); // non-local name - check(types::MR, + check( + types::MR, "newmailbox.example.com.", None, b"\x0anewmailbox\x07example\x03com\x00", @@ -231,13 +215,10 @@ fn test_MR() { #[test] fn test_PTR() { // local name - check(types::PTR, - "ptr.rec.test.", - None, - b"\x03ptr\xc0\x11", - ); + check(types::PTR, "ptr.rec.test.", None, b"\x03ptr\xc0\x11"); // non-local name - check(types::PTR, + check( + types::PTR, "ptr.example.com.", None, b"\x03ptr\x07example\x03com\x00", @@ -246,22 +227,26 @@ fn test_PTR() { #[test] fn test_HINFO() { - check(types::HINFO, + check( + types::HINFO, "\"i686\" \"Linux\"", None, b"\x04i686\x05Linux", ); - check(types::HINFO, + check( + types::HINFO, "i686 \"Linux\"", Some("\"i686\" \"Linux\""), b"\x04i686\x05Linux", ); - check(types::HINFO, + check( + types::HINFO, "\"i686\" Linux", Some("\"i686\" \"Linux\""), b"\x04i686\x05Linux", ); - check(types::HINFO, + check( + types::HINFO, "i686 Linux", Some("\"i686\" \"Linux\""), b"\x04i686\x05Linux", @@ -273,56 +258,53 @@ fn test_HINFO() { #[test] fn test_MX() { // local name - check(types::MX, + check( + types::MX, "10 mx.rec.test.", None, b"\x00\x0a\x02mx\xc0\x11", ); // non-local name - check(types::MX, + check( + types::MX, "20 mx.example.com.", None, b"\x00\x14\x02mx\x07example\x03com\x00", ); // root label - check(types::MX, - "20 .", - None, - b"\x00\x14\x00", - ); + check(types::MX, "20 .", None, b"\x00\x14\x00"); } #[test] fn test_TXT() { - check(types::TXT, - "\"short text\"", - None, - b"\x0ashort text", - ); + check(types::TXT, "\"short text\"", None, b"\x0ashort text"); check(types::TXT, "\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\"", None, b"\xfflong record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a2222222222", ); // autosplitting not supported -/* - check(types::TXT, - "\"long record test 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222\"", - Some("\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\""), - b"\xfflong record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a2222222222", - ); -*/ - check(types::TXT, + /* + check(types::TXT, + "\"long record test 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222\"", + Some("\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\""), + b"\xfflong record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a2222222222", + ); + */ + check( + types::TXT, "\"\\195\\133LAND ISLANDS\"", None, b"\x0e\xc3\x85LAND ISLANDS", ); - check(types::TXT, + check( + types::TXT, "\"\u{00c5}LAND ISLANDS\"", Some("\"\\195\\133LAND ISLANDS\""), b"\x0e\xc3\x85LAND ISLANDS", ); - check(types::TXT, + check( + types::TXT, "\"nonbreakingtxt\"", None, b"\x0enonbreakingtxt", @@ -332,13 +314,15 @@ fn test_TXT() { #[test] fn test_RP() { // local name - check(types::RP, + check( + types::RP, "admin.rec.test. admin-info.rec.test.", None, b"\x05admin\x03rec\x04test\x00\x0aadmin-info\x03rec\x04test\x00", ); // non-local name - check(types::RP, + check( + types::RP, "admin.example.com. admin-info.example.com.", None, b"\x05admin\x07example\x03com\x00\x0aadmin-info\x07example\x03com\x00", @@ -348,13 +332,15 @@ fn test_RP() { #[test] fn test_AFSDB() { // local name - check(types::AFSDB, + check( + types::AFSDB, "1 afs-server.rec.test.", None, b"\x00\x01\x0aafs-server\x03rec\x04test\x00", ); // non-local name - check(types::AFSDB, + check( + types::AFSDB, "1 afs-server.example.com.", None, b"\x00\x01\x0aafs-server\x07example\x03com\x00", @@ -390,17 +376,20 @@ fn test_KEY() { #[test] fn test_AAAA() { - check(types::AAAA, + check( + types::AAAA, "fe80::250:56ff:fe9b:114", None, b"\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14", ); - check(types::AAAA, + check( + types::AAAA, "2a02:1b8:10:2::151", None, b"\x2a\x02\x01\xb8\x00\x10\x00\x02\x00\x00\x00\x00\x00\x00\x01\x51", ); - check(types::AAAA, + check( + types::AAAA, "::1", None, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", @@ -409,22 +398,26 @@ fn test_AAAA() { #[test] fn test_LOC() { - check(types::LOC, + check( + types::LOC, "32 7 19 S 116 2 25 E", Some("32 7 19.000 S 116 2 25.000 E 0.00m 1.00m 10000.00m 10.00m"), b"\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x96\x80", ); - check(types::LOC, + check( + types::LOC, "32 7 19 S 116 2 25 E 10m", Some("32 7 19.000 S 116 2 25.000 E 10.00m 1.00m 10000.00m 10.00m"), b"\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x9a\x68", ); - check(types::LOC, + check( + types::LOC, "42 21 54 N 71 06 18 W -24m 30m", Some("42 21 54.000 N 71 6 18.000 W -24.00m 30.00m 10000.00m 10.00m"), b"\x00\x33\x16\x13\x89\x17\x2d\xd0\x70\xbe\x15\xf0\x00\x98\x8d\x20", ); - check(types::LOC, + check( + types::LOC, "42 21 43.952 N 71 5 6.344 W -24m 1m 200m", Some("42 21 43.952 N 71 5 6.344 W -24.00m 1.00m 200.00m 10.00m"), b"\x00\x12\x24\x13\x89\x17\x06\x90\x70\xbf\x2d\xd8\x00\x98\x8d\x20", @@ -436,19 +429,22 @@ fn test_LOC() { #[test] fn test_SRV() { // local name - check(types::SRV, + check( + types::SRV, "10 10 5060 sip.rec.test.", None, b"\x00\x0a\x00\x0a\x13\xc4\x03sip\x03rec\x04test\x00", ); // non-local name - check(types::SRV, + check( + types::SRV, "10 10 5060 sip.example.com.", None, b"\x00\x0a\x00\x0a\x13\xc4\x03sip\x07example\x03com\x00", ); // root name - check(types::SRV, + check( + types::SRV, "10 10 5060 .", None, b"\x00\x0a\x00\x0a\x13\xc4\x00", @@ -457,12 +453,14 @@ fn test_SRV() { #[test] fn test_NAPTR() { - check(types::NAPTR, + check( + types::NAPTR, "100 10 \"\" \"\" \"/urn:cid:.+@([^\\\\.]+\\\\.)(.*)$/\\\\2/i\" .", None, b"\x00\x64\x00\x0a\x00\x00\x20/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\x00", ); - check(types::NAPTR, + check( + types::NAPTR, "100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.rec.test.", None, b"\x00\x64\x00\x32\x01s\x10http+I2L+I2C+I2R\x00\x05_http\x04_tcp\x03rec\x04test\x00", @@ -471,7 +469,8 @@ fn test_NAPTR() { #[test] fn test_KX() { - check(types::KX, + check( + types::KX, "10 mail.rec.test.", None, b"\x00\x0a\x04mail\x03rec\x04test\x00", @@ -507,13 +506,15 @@ fn test_DS() { #[test] fn test_SSHFP() { - check(types::SSHFP, + check( + types::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", None, b"\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88", ); - // as per RFC4025 - check(types::SSHFP, + // as per RFC4025 + check( + types::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc253 8d88", Some("1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88"), b"\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88", @@ -523,22 +524,20 @@ fn test_SSHFP() { #[test] fn test_IPSECKEY() { // as per RFC4025 - check(types::IPSECKEY, - "255 0 0", - None, - b"\xff\x00\x00", - ); + check(types::IPSECKEY, "255 0 0", None, b"\xff\x00\x00"); check(types::IPSECKEY, "255 0 1 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", None, b"\xff\x00\x01\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52", ); - check(types::IPSECKEY, + check( + types::IPSECKEY, "255 1 0 127.0.0.1", None, b"\xff\x01\x00\x7f\x00\x00\x01", ); - check(types::IPSECKEY, + check( + types::IPSECKEY, "255 2 0 fe80::250:56ff:fe9b:114", None, b"\xff\x02\x00\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14", @@ -573,7 +572,8 @@ fn test_RRSIG() { #[test] fn test_NSEC() { - check(types::NSEC, + check( + types::NSEC, "a.rec.test. A NS SOA MX AAAA RRSIG NSEC DNSKEY", None, b"\x01a\x03rec\x04test\x00\x00\x07\x62\x01\x00\x08\x00\x03\x80", @@ -619,7 +619,8 @@ fn test_NSEC3() { #[test] fn test_NSEC3PARAM() { - check(types::NSEC3PARAM, + check( + types::NSEC3PARAM, "1 0 1 f00b", None, b"\x01\x00\x00\x01\x02\xf0\x0b", @@ -751,7 +752,8 @@ fn test_OPENPGPKEY() { #[test] fn test_SPF() { - check(types::SPF, + check( + types::SPF, "\"v=spf1 a:mail.rec.test ~all\"", None, b"\x1bv=spf1 a:mail.rec.test ~all", @@ -760,7 +762,8 @@ fn test_SPF() { #[test] fn test_EUI48() { - check(types::EUI48, + check( + types::EUI48, "00-11-22-33-44-55", None, b"\x00\x11\x22\x33\x44\x55", @@ -769,7 +772,8 @@ fn test_EUI48() { #[test] fn test_EUI64() { - check(types::EUI64, + check( + types::EUI64, "00-11-22-33-44-55-66-77", None, b"\x00\x11\x22\x33\x44\x55\x66\x77", @@ -778,7 +782,8 @@ fn test_EUI64() { #[test] fn test_TKEY() { - check(types::TKEY, + check( + types::TKEY, "gss-tsig. 12345 12345 3 21 4 dGVzdA== 4 dGVzdA==", None, b"\x08gss-tsig\x00\x00\x00\x30\x39\x00\x00\x30\x39\x00\x03\x00\x15\x00\x04test\x00\x04test", @@ -815,7 +820,8 @@ fn test_URI() { #[test] fn test_CAA() { - check(types::CAA, + check( + types::CAA, "0 issue \"example.net\"", None, b"\x00\x05\x69\x73\x73\x75\x65\x65\x78\x61\x6d\x70\x6c\x65\x2e\x6e\x65\x74", @@ -835,10 +841,14 @@ fn test_DLV() { fn test_TYPE65226() { let d1 = text::parse_with("\\# 3 414243", |data| { super::UnknownRecord::dns_parse(types::Type(65226), data) - }).unwrap(); + }) + .unwrap(); let d2 = super::UnknownRecord::new(types::Type(65226), Bytes::from_static(b"\x41\x42\x43")); assert_eq!(d1, d2); - assert_eq!(d1.text().unwrap(), ("TYPE65226".into(), "\\# 3 414243".into())); + assert_eq!( + d1.text().unwrap(), + ("TYPE65226".into(), "\\# 3 414243".into()) + ); } fn check_invalid_zone(q: Type, text_input: &str) { @@ -848,9 +858,7 @@ fn check_invalid_zone(q: Type, text_input: &str) { context.set_record_type(q); context.set_last_ttl(3600); - text::parse_with(text_input, |data| { - registry::parse_rr_data(&context, data) - }).unwrap_err(); + text::parse_with(text_input, |data| registry::parse_rr_data(&context, data)).unwrap_err(); } fn check_invalid_wire(q: Type, raw: &'static [u8]) { @@ -873,16 +881,25 @@ fn test_invalid_data_checks() { check_invalid_zone(types::AAAA, "23:00"); // time when this test was written check_invalid_zone(types::AAAA, "23:00::15::43"); // double compression check_invalid_zone(types::AAAA, "2a23:00::15::"); // ditto - check_invalid_wire(types::AAAA, b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"); // truncated wire value -// empty label, must be broken + check_invalid_wire( + types::AAAA, + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff", + ); // truncated wire value + // empty label, must be broken check_invalid_zone(types::CNAME, "name..example.com."); -// overly large label (64), must be broken - check_invalid_zone(types::CNAME, "1234567890123456789012345678901234567890123456789012345678901234.example.com."); -// local overly large name (256), must be broken + // overly large label (64), must be broken + check_invalid_zone( + types::CNAME, + "1234567890123456789012345678901234567890123456789012345678901234.example.com.", + ); + // local overly large name (256), must be broken check_invalid_zone(types::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123.rec.test."); -// non-local overly large name (256), must be broken + // non-local overly large name (256), must be broken check_invalid_zone(types::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012."); - check_invalid_zone(types::SOA, "ns.rec.test hostmaster.test.rec 20130512010 3600 3600 604800 120"); // too long serial + check_invalid_zone( + types::SOA, + "ns.rec.test hostmaster.test.rec 20130512010 3600 3600 604800 120", + ); // too long serial } #[test] @@ -895,42 +912,39 @@ fn test_opt_record_in() { let opt = p.opt.unwrap().unwrap(); assert_eq!(opt.udp_payload_size, 1280); - assert_eq!(opt.options, vec![ - DnsOption::NSID(Bytes::from_static(b"powerdns")), - ]); + assert_eq!( + opt.options, + vec![DnsOption::NSID(Bytes::from_static(b"powerdns")),] + ); } #[test] fn test_opt_record_out() { - let mut p = DnsPacket{ + let mut p = DnsPacket { id: 0xf001, flags: DnsHeaderFlags { recursion_desired: true, - .. Default::default() + ..Default::default() }, - question: vec![ - Question { - qname: "www.powerdns.com.".parse().unwrap(), - qtype: types::A, - qclass: classes::IN, - } - ], - answer: vec![ - Resource { - name: "www.powerdns.com.".parse().unwrap(), - class: classes::IN, - ttl: 16, - data: Box::new(A { addr: "127.0.0.1".parse().unwrap() }), - } - ], + question: vec![Question { + qname: "www.powerdns.com.".parse().unwrap(), + qtype: types::A, + qclass: classes::IN, + }], + answer: vec![Resource { + name: "www.powerdns.com.".parse().unwrap(), + class: classes::IN, + ttl: 16, + data: Box::new(A { + addr: "127.0.0.1".parse().unwrap(), + }), + }], opt: Some(Ok(Opt { udp_payload_size: 1280, - options: vec![ - DnsOption::NSID(Bytes::from_static(b"powerdns")), - ], - .. Default::default() + options: vec![DnsOption::NSID(Bytes::from_static(b"powerdns"))], + ..Default::default() })), - .. Default::default() + ..Default::default() }; assert_eq!( diff --git a/lib/dnsbox-base/src/records/registry.rs b/lib/dnsbox-base/src/records/registry.rs index 0a70cb3..d8eb0ac 100644 --- a/lib/dnsbox-base/src/records/registry.rs +++ b/lib/dnsbox-base/src/records/registry.rs @@ -4,16 +4,16 @@ use std::collections::HashMap; use std::io::Cursor; use std::marker::PhantomData; -use crate::common_types::{Class, Type, types}; +use crate::common_types::{types, Class, Type}; use crate::errors::*; use crate::records::structs; -use crate::ser::{RRData, StaticRRData}; use crate::ser::text::DnsTextContext; +use crate::ser::{RRData, StaticRRData}; // this should be enough for registered names const TYPE_NAME_MAX_LEN: usize = 16; -lazy_static::lazy_static!{ +lazy_static::lazy_static! { static ref REGISTRY: Registry = Registry::init(); } @@ -22,7 +22,9 @@ fn registry() -> &'static Registry { } pub(crate) fn lookup_type_name(name: &str) -> Option { - if name.len() >= TYPE_NAME_MAX_LEN { return None; } + 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()); @@ -42,7 +44,12 @@ pub fn known_name_to_type(name: &str) -> Option { Some(t) } -pub fn deserialize_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor) -> Result> { +pub fn deserialize_rr_data( + ttl: u32, + rr_class: Class, + rr_type: Type, + data: &mut Cursor, +) -> Result> { let registry = registry(); match registry.type_parser.get(&rr_type) { Some(p) => p.deserialize_rr_data(ttl, rr_class, rr_type, data), @@ -80,13 +87,25 @@ trait RRDataTypeParse: 'static { TypeId::of::() } - fn deserialize_rr_data(&self, ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor) -> Result>; + fn deserialize_rr_data( + &self, + ttl: u32, + rr_class: Class, + rr_type: Type, + data: &mut Cursor, + ) -> Result>; fn parse_rr_data(&self, context: &DnsTextContext, data: &mut &str) -> Result>; } impl RRDataTypeParse for TagRRDataType { - fn deserialize_rr_data(&self, ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor) -> Result> { + fn deserialize_rr_data( + &self, + ttl: u32, + rr_class: Class, + rr_type: Type, + data: &mut Cursor, + ) -> Result> { T::deserialize_rr_data(ttl, rr_class, rr_type, data).map(|d| Box::new(d) as _) } @@ -122,8 +141,8 @@ impl Registry { r.register_known::(); r.register_known::(); r.register_known::(); - r.register_unknown("NULL" , types::NULL); - r.register_unknown("WKS" , types::WKS); + r.register_unknown("NULL", types::NULL); + r.register_unknown("WKS", types::WKS); r.register_known::(); r.register_known::(); r.register_known::(); @@ -131,10 +150,10 @@ impl Registry { r.register_known::(); r.register_known::(); r.register_known::(); - r.register_unknown("X25" , types::X25); - r.register_unknown("ISDN" , types::ISDN); + r.register_unknown("X25", types::X25); + r.register_unknown("ISDN", types::ISDN); r.register_known::(); - r.register_unknown("NSAP" , types::NSAP); + r.register_unknown("NSAP", types::NSAP); r.register_known::(); r.register_known::(); r.register_known::(); @@ -143,17 +162,17 @@ impl Registry { r.register_known::(); r.register_known::(); r.register_known::(); - r.register_unknown("EID" , types::EID); - r.register_unknown("NIMLOC" , types::NIMLOC); + r.register_unknown("EID", types::EID); + r.register_unknown("NIMLOC", types::NIMLOC); r.register_known::(); - r.register_unknown("ATMA" , types::ATMA); + r.register_unknown("ATMA", types::ATMA); r.register_known::(); r.register_known::(); r.register_known::(); r.register_known::(); r.register_known::(); - r.register_unknown("SINK" , types::SINK); - r.register_unknown("OPT" , types::OPT); + r.register_unknown("SINK", types::SINK); + r.register_unknown("OPT", types::OPT); r.register_known::(); r.register_known::(); r.register_known::(); @@ -166,39 +185,39 @@ impl Registry { r.register_known::(); r.register_known::(); r.register_known::(); - r.register_unknown("HIP" , types::HIP); + r.register_unknown("HIP", types::HIP); r.register_known::(); r.register_known::(); - r.register_unknown("TALINK" , types::TALINK); + r.register_unknown("TALINK", types::TALINK); r.register_known::(); r.register_known::(); r.register_known::(); - r.register_unknown("CSYNC" , types::CSYNC); - r.register_unknown("ZONEMD" , types::ZONEMD); + r.register_unknown("CSYNC", types::CSYNC); + r.register_unknown("ZONEMD", types::ZONEMD); r.register_known::(); - 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_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::(); r.register_known::(); r.register_known::(); r.register_known::(); - 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_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::(); r.register_known::(); - 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_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::(); r.register_known::(); @@ -213,9 +232,20 @@ impl Registry { 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()); + 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); } @@ -227,12 +257,16 @@ impl Registry { let rrtype = T::TYPE; let name = T::NAME; self.register_name(name, rrtype); - self.type_parser.insert(rrtype, Box::new(TagRRDataType::(PhantomData))); + self.type_parser + .insert(rrtype, Box::new(TagRRDataType::(PhantomData))); } fn check_registration(&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 p: &dyn RRDataTypeParse = &**self + .type_parser + .get(&T::TYPE) + .expect("no parser registered"); let tid = TypeId::of::>(); assert_eq!(p.type_id(), tid); } diff --git a/lib/dnsbox-base/src/records/structs.rs b/lib/dnsbox-base/src/records/structs.rs index 618bbba..3cff46c 100644 --- a/lib/dnsbox-base/src/records/structs.rs +++ b/lib/dnsbox-base/src/records/structs.rs @@ -354,28 +354,42 @@ pub struct DNSKEY { impl DNSKEY { fn alg1_tag(&self) -> u16 { let key: &[u8] = &self.public_key; - if key.is_empty() { return 0; } // not enough data + if key.is_empty() { + return 0; + } // not enough data let pkey; if 0 == key[0] { // two-byte length encoding of exponent - if key.len() < 3 { return 0; } // not enough data + if key.len() < 3 { + return 0; + } // not enough data let explen = ((key[1] as u16) << 8) + (key[2] as u16); - if explen < 256 { return 0; } // should have used shorter length encoding - if key.len() < 3 + (explen as usize) { return 0; } // not enough data + if explen < 256 { + return 0; + } // should have used shorter length encoding + if key.len() < 3 + (explen as usize) { + return 0; + } // not enough data pkey = &key[3 + (explen as usize)..]; } else { // one-byte length encoding of exponent let explen = key[0]; - if key.len() < 1 + (explen as usize) { return 0; } // not enough data + if key.len() < 1 + (explen as usize) { + return 0; + } // not enough data pkey = &key[1 + (explen as usize)..]; } - if pkey.len() < 3 { return 0; } // not enough data + if pkey.len() < 3 { + return 0; + } // not enough data ((pkey[pkey.len() - 3] as u16) << 8) + (pkey[pkey.len() - 3] as u16) } /// calculate key tag pub fn tag(&self) -> u16 { - if self.algorithm == DnsSecAlgorithm::RSAMD5 { return self.alg1_tag(); } + if self.algorithm == DnsSecAlgorithm::RSAMD5 { + return self.alg1_tag(); + } let mut sum = 0u32; @@ -395,7 +409,9 @@ impl DNSKEY { #[cfg(feature = "crypto")] pub fn build_ds(&self, zone: &DnsName, algs: &[DnsSecDigestAlgorithmKnown]) -> Result> { - if algs.is_empty() { return Ok(Vec::new()); } + if algs.is_empty() { + return Ok(Vec::new()); + } use crate::ser::packet::DnsPacketWriteContext; let mut ctx = DnsPacketWriteContext::new(); @@ -406,12 +422,15 @@ impl DNSKEY { let key_tag = self.tag(); - Ok(algs.iter().map(|alg| DS { - key_tag, - algorithm: self.algorithm, - digest_type: (*alg).into(), - digest: HexRemainingBlob::new(crate::crypto::ds_hash(*alg, &bin)), - }).collect()) + Ok(algs + .iter() + .map(|alg| DS { + key_tag, + algorithm: self.algorithm, + digest_type: (*alg).into(), + digest: HexRemainingBlob::new(crate::crypto::ds_hash(*alg, &bin)), + }) + .collect()) } #[cfg(feature = "crypto")] @@ -476,7 +495,6 @@ pub struct NINFO { pub text: LongText, } - #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct RKEY { @@ -515,7 +533,8 @@ impl CDNSKEY { protocol: self.protocol, algorithm: self.algorithm, public_key: self.public_key.clone(), - }.tag() + } + .tag() } } @@ -585,7 +604,7 @@ pub struct EUI48 { #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] #[RRClass(ANY)] pub struct EUI64 { - pub addr: EUI64Addr + pub addr: EUI64Addr, } #[derive(Clone, PartialEq, Eq, Debug, DnsPacketData, DnsTextData, RRData)] diff --git a/lib/dnsbox-base/src/records/tests.rs b/lib/dnsbox-base/src/records/tests.rs index d3bd1da..1d7b523 100644 --- a/lib/dnsbox-base/src/records/tests.rs +++ b/lib/dnsbox-base/src/records/tests.rs @@ -1,15 +1,15 @@ -use bytes::{Bytes, Buf}; use crate::common_types::classes; -use failure::ResultExt; use crate::records::structs; -use crate::ser::{StaticRRData, packet, text}; use crate::ser::packet::DnsPacketData; +use crate::ser::{packet, text, StaticRRData}; +use bytes::{Buf, Bytes}; +use failure::ResultExt; use std::fmt; use std::io::Cursor; fn rrdata_de(data: &'static [u8]) -> crate::errors::Result where - T: StaticRRData + T: StaticRRData, { let mut data = Cursor::new(Bytes::from_static(data)); let result = T::deserialize_rr_data(3600, classes::IN, T::TYPE, &mut data)?; @@ -19,20 +19,18 @@ where fn rrdata_parse(data: &str) -> crate::errors::Result where - T: StaticRRData + T: StaticRRData, { let mut ctx = text::DnsTextContext::new(); ctx.set_zone_class(classes::IN); ctx.set_record_type(T::TYPE); ctx.set_last_ttl(3600); - text::parse_with(data, |data| { - T::dns_parse_rr_data(&ctx, data) - }) + text::parse_with(data, |data| T::dns_parse_rr_data(&ctx, data)) } fn check(txt: &str, data: &'static [u8]) -> crate::errors::Result<()> where - T: StaticRRData + fmt::Debug + PartialEq + T: StaticRRData + fmt::Debug + PartialEq, { let d1: T = rrdata_de(data).context("couldn't parse binary record")?; let d2: T = rrdata_parse(txt).context("couldn't parse text record")?; @@ -42,7 +40,7 @@ where fn check2(txt: &str, data: &'static [u8], canon: &str) -> crate::errors::Result<()> where - T: StaticRRData + fmt::Debug + PartialEq + T: StaticRRData + fmt::Debug + PartialEq, { let d1: T = rrdata_de(data).context("couldn't parse binary record")?; let d2: T = rrdata_parse(txt).context("couldn't parse text record")?; @@ -52,8 +50,18 @@ where let d2_text = d2.text().unwrap(); let canon_text = (T::NAME.to_owned(), canon.into()); - failure::ensure!(d1_text == canon_text, "re-formatted binary record not equal to canonical representation: {:?} != {:?}", d1_text, canon_text); - failure::ensure!(d2_text == canon_text, "re-formatted text record not equal to canonical representation: {:?} != {:?}", d2_text, canon_text); + failure::ensure!( + d1_text == canon_text, + "re-formatted binary record not equal to canonical representation: {:?} != {:?}", + d1_text, + canon_text + ); + failure::ensure!( + d2_text == canon_text, + "re-formatted text record not equal to canonical representation: {:?} != {:?}", + d2_text, + canon_text + ); Ok(()) } @@ -70,7 +78,7 @@ fn test_mx() { fn test_txt_for() where - T: StaticRRData + fmt::Debug + PartialEq + T: StaticRRData + fmt::Debug + PartialEq, { // at least one "segment" (which could be empty) check2::(r#" "" "#, b"", r#""""#).unwrap_err(); @@ -85,7 +93,9 @@ where { let mut s = String::new(); s.push('"'); - for _ in 0..256 { s.push('a'); } + for _ in 0..256 { + s.push('a'); + } s.push('"'); rrdata_parse::(&s).unwrap_err(); } @@ -107,8 +117,16 @@ fn test_ds() { fn test_nsec() { check::("foo.bar. ", b"\x03foo\x03bar\x00").unwrap(); check::("foo.bar. A NS ", b"\x03foo\x03bar\x00\x00\x01\x60").unwrap(); - check::("foo.bar. A NS SOA MX AAAA RRSIG NSEC DNSKEY ", b"\x03foo\x03bar\x00\x00\x07\x62\x01\x00\x08\x00\x03\x80").unwrap(); - check::("foo.bar. A NS TYPE256 TYPE65280 ", b"\x03foo\x03bar\x00\x00\x01\x60\x01\x01\x80\xff\x01\x80").unwrap(); + check::( + "foo.bar. A NS SOA MX AAAA RRSIG NSEC DNSKEY ", + b"\x03foo\x03bar\x00\x00\x07\x62\x01\x00\x08\x00\x03\x80", + ) + .unwrap(); + check::( + "foo.bar. A NS TYPE256 TYPE65280 ", + b"\x03foo\x03bar\x00\x00\x01\x60\x01\x01\x80\xff\x01\x80", + ) + .unwrap(); } #[test] @@ -121,15 +139,27 @@ fn test_dnskey() { #[test] fn test_nsec3() { check::("1 2 300 - vs", b"\x01\x02\x01\x2c\x00\x01\xff").unwrap(); - check::("1 2 300 - vs A NS", b"\x01\x02\x01\x2c\x00\x01\xff\x00\x01\x60").unwrap(); - check::("1 2 300 ab vs A NS", b"\x01\x02\x01\x2c\x01\xab\x01\xff\x00\x01\x60").unwrap(); + check::( + "1 2 300 - vs A NS", + b"\x01\x02\x01\x2c\x00\x01\xff\x00\x01\x60", + ) + .unwrap(); + check::( + "1 2 300 ab vs A NS", + b"\x01\x02\x01\x2c\x01\xab\x01\xff\x00\x01\x60", + ) + .unwrap(); // invalid base32 texts rrdata_parse::("1 2 300 - v").unwrap_err(); rrdata_parse::("1 2 300 - vv").unwrap_err(); // invalid (empty) next-hashed values - packet::deserialize_with(Bytes::from_static(b"\x01\x02\x01\x2c\x00\x00"), structs::NSEC3::deserialize).unwrap_err(); + packet::deserialize_with( + Bytes::from_static(b"\x01\x02\x01\x2c\x00\x00"), + structs::NSEC3::deserialize, + ) + .unwrap_err(); } #[test] @@ -151,5 +181,9 @@ fn test_apl() { check::("!1:0.0.0.0/0", b"\x00\x01\x00\x80").unwrap(); check::("2:::/0", b"\x00\x02\x00\x00").unwrap(); check::("!2:::/0", b"\x00\x02\x00\x80").unwrap(); - check::("1:192.0.2.0/24 !2:2001:db8::/32", b"\x00\x01\x18\x03\xc0\x00\x02\x00\x02\x20\x84\x20\x01\x0d\xb8").unwrap(); + check::( + "1:192.0.2.0/24 !2:2001:db8::/32", + b"\x00\x01\x18\x03\xc0\x00\x02\x00\x02\x20\x84\x20\x01\x0d\xb8", + ) + .unwrap(); } diff --git a/lib/dnsbox-base/src/records/unknown.rs b/lib/dnsbox-base/src/records/unknown.rs index 1dc83ec..941cc0a 100644 --- a/lib/dnsbox-base/src/records/unknown.rs +++ b/lib/dnsbox-base/src/records/unknown.rs @@ -1,11 +1,11 @@ -use bytes::{Bytes, BufMut}; -use crate::common_types::*; use crate::common_types::binary::HEXLOWER_PERMISSIVE_ALLOW_WS; +use crate::common_types::*; use crate::errors::*; -use failure::{ResultExt, Fail}; -use crate::ser::packet::{DnsPacketWriteContext, remaining_bytes}; +use crate::ser::packet::{remaining_bytes, DnsPacketWriteContext}; +use crate::ser::text::{next_field, DnsTextContext, DnsTextFormatter}; use crate::ser::{RRData, RRDataPacket, RRDataText}; -use crate::ser::text::{DnsTextFormatter, DnsTextContext, next_field}; +use bytes::{BufMut, Bytes}; +use failure::{Fail, ResultExt}; use std::borrow::Cow; use std::fmt; use std::io::Cursor; @@ -38,9 +38,15 @@ impl UnknownRecord { let field = next_field(data).context("generic record data length")?; let len: usize = field.parse()?; - let result = HEXLOWER_PERMISSIVE_ALLOW_WS.decode(data.as_bytes()) + let result = HEXLOWER_PERMISSIVE_ALLOW_WS + .decode(data.as_bytes()) .with_context(|e| e.context(format!("invalid hex: {:?}", data)))?; - failure::ensure!(len == result.len(), "length {} doesn't match length of encoded data {}", len, result.len()); + failure::ensure!( + len == result.len(), + "length {} doesn't match length of encoded data {}", + len, + result.len() + ); *data = ""; // read all data Ok(UnknownRecord { @@ -51,7 +57,12 @@ impl UnknownRecord { } impl RRDataPacket for UnknownRecord { - fn deserialize_rr_data(_ttl: u32, _rr_class: Class, rr_type: Type, data: &mut Cursor) -> Result { + fn deserialize_rr_data( + _ttl: u32, + _rr_class: Class, + rr_type: Type, + data: &mut Cursor, + ) -> Result { UnknownRecord::deserialize(rr_type, data) } @@ -59,7 +70,11 @@ impl RRDataPacket for UnknownRecord { self.rr_type } - fn serialize_rr_data(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { + fn serialize_rr_data( + &self, + _context: &mut DnsPacketWriteContext, + packet: &mut Vec, + ) -> Result<()> { packet.reserve(self.raw.len()); packet.put_slice(&self.raw); Ok(()) @@ -81,7 +96,12 @@ impl RRDataText for UnknownRecord { /// this must never fail unless the underlying buffer fails. fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result { - write!(f, "\\# {} {}", self.raw.len(), HEXLOWER_PERMISSIVE_ALLOW_WS.encode(&self.raw)) + write!( + f, + "\\# {} {}", + self.raw.len(), + HEXLOWER_PERMISSIVE_ALLOW_WS.encode(&self.raw) + ) } fn rr_type_txt(&self) -> Cow<'static, str> { diff --git a/lib/dnsbox-base/src/records/weird_structs.rs b/lib/dnsbox-base/src/records/weird_structs.rs index 83b8ee1..fea32c3 100644 --- a/lib/dnsbox-base/src/records/weird_structs.rs +++ b/lib/dnsbox-base/src/records/weird_structs.rs @@ -1,10 +1,10 @@ -use bytes::{Bytes, Buf, BufMut}; -use crate::errors::*; use crate::common_types::*; -use failure::ResultExt; +use crate::errors::*; +use crate::ser::packet::{get_blob, remaining_bytes, DnsPacketData, DnsPacketWriteContext}; +use crate::ser::text::{next_field, DnsTextContext, DnsTextData, DnsTextFormatter}; use crate::ser::RRData; -use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext, remaining_bytes, get_blob}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; +use bytes::{Buf, BufMut, Bytes}; +use failure::ResultExt; use std::fmt; use std::io::Read; use std::net::{Ipv4Addr, Ipv6Addr}; @@ -17,10 +17,7 @@ use std::net::{Ipv4Addr, Ipv6Addr}; #[RRClass(ANY)] pub enum LOC { Version0(LOC0), - UnknownVersion{ - version: u8, - data: Bytes, - }, + UnknownVersion { version: u8, data: Bytes }, } impl DnsPacketData for LOC { @@ -29,7 +26,7 @@ impl DnsPacketData for LOC { if 0 == version { Ok(LOC::Version0(DnsPacketData::deserialize(data)?)) } else { - Ok(LOC::UnknownVersion{ + Ok(LOC::UnknownVersion { version: version, data: remaining_bytes(data), }) @@ -43,7 +40,7 @@ impl DnsPacketData for LOC { packet.put_u8(0); l0.serialize(context, packet) }, - LOC::UnknownVersion{version, ref data} => { + LOC::UnknownVersion { version, ref data } => { packet.reserve(data.len() + 1); packet.put_u8(version); packet.put_slice(data); @@ -56,53 +53,85 @@ impl DnsPacketData for LOC { impl DnsTextData for LOC { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result { let degrees_latitude = next_field(data)?.parse::()?; - failure::ensure!(degrees_latitude <= 90, "degrees latitude out of range: {}", degrees_latitude); + failure::ensure!( + degrees_latitude <= 90, + "degrees latitude out of range: {}", + degrees_latitude + ); let mut minutes_latitude = 0; let mut seconds_latitude = 0.0; let mut field = next_field(data)?; if field != "N" && field != "n" && field != "S" && field != "s" { minutes_latitude = field.parse::()?; - failure::ensure!(minutes_latitude < 60, "minutes latitude out of range: {}", minutes_latitude); + failure::ensure!( + minutes_latitude < 60, + "minutes latitude out of range: {}", + minutes_latitude + ); field = next_field(data)?; if field != "N" && field != "n" && field != "S" && field != "s" { seconds_latitude = field.parse::()?; - failure::ensure!(seconds_latitude >= 0.0 && seconds_latitude < 60.0, "seconds latitude out of range: {}", seconds_latitude); + failure::ensure!( + seconds_latitude >= 0.0 && seconds_latitude < 60.0, + "seconds latitude out of range: {}", + seconds_latitude + ); field = next_field(data)?; } } - let latitude_off = (3600_000 * degrees_latitude as u32) + (60_000 * minutes_latitude as u32) + (1_000.0 * seconds_latitude).round() as u32; + let latitude_off = (3600_000 * degrees_latitude as u32) + + (60_000 * minutes_latitude as u32) + + (1_000.0 * seconds_latitude).round() as u32; failure::ensure!(latitude_off <= 3600_000 * 180, "latitude out of range"); let latitude = match field { - "N"|"n" => 0x8000_0000 + latitude_off, - "S"|"s" => 0x8000_0000 - latitude_off, + "N" | "n" => 0x8000_0000 + latitude_off, + "S" | "s" => 0x8000_0000 - latitude_off, _ => failure::bail!("invalid latitude orientation [NS]: {}", field), }; let degrees_longitude = next_field(data)?.parse::()?; - failure::ensure!(degrees_longitude <= 180, "degrees longitude out of range: {}", degrees_longitude); + failure::ensure!( + degrees_longitude <= 180, + "degrees longitude out of range: {}", + degrees_longitude + ); let mut minutes_longitude = 0; let mut seconds_longitude = 0.0; let mut field = next_field(data)?; if field != "E" && field != "e" && field != "W" && field != "w" { minutes_longitude = field.parse::()?; - failure::ensure!(minutes_longitude < 60, "minutes longitude out of range: {}", minutes_longitude); + failure::ensure!( + minutes_longitude < 60, + "minutes longitude out of range: {}", + minutes_longitude + ); field = next_field(data)?; if field != "E" && field != "e" && field != "W" && field != "w" { seconds_longitude = field.parse::()?; - failure::ensure!(seconds_longitude >= 0.0 && seconds_longitude < 60.0, "seconds longitude out of range: {}", seconds_longitude); + failure::ensure!( + seconds_longitude >= 0.0 && seconds_longitude < 60.0, + "seconds longitude out of range: {}", + seconds_longitude + ); field = next_field(data)?; } } - let longitude_off = (3600_000 * degrees_longitude as u32) + (60_000 * minutes_longitude as u32) + (1_000.0 * seconds_longitude).round() as u32; + let longitude_off = (3600_000 * degrees_longitude as u32) + + (60_000 * minutes_longitude as u32) + + (1_000.0 * seconds_longitude).round() as u32; failure::ensure!(longitude_off <= 3600_000 * 180, "longitude out of range"); let longitude = match field { - "E"|"e" => 0x8000_0000 + longitude_off, - "W"|"w" => 0x8000_0000 - longitude_off, + "E" | "e" => 0x8000_0000 + longitude_off, + "W" | "w" => 0x8000_0000 - longitude_off, _ => failure::bail!("invalid longitude orientation [EW]: {}", field), }; fn trim_unit_m(s: &str) -> &str { - if s.ends_with('m') { &s[..s.len()-1] } else { s } + if s.ends_with('m') { + &s[..s.len() - 1] + } else { + s + } } fn parse_precision(s: &str) -> Result { @@ -112,13 +141,23 @@ impl DnsTextData for LOC { let mut dec_point = None; for &b in s.as_bytes() { if b == b'.' { - failure::ensure!(dec_point.is_none(), "invalid precision (double decimal point): {:?}", s); + failure::ensure!( + dec_point.is_none(), + "invalid precision (double decimal point): {:?}", + s + ); dec_point = Some(0); continue; } - failure::ensure!(b >= b'0' && b <= b'9', "invalid precision (invalid character): {:?}", s); + failure::ensure!( + b >= b'0' && b <= b'9', + "invalid precision (invalid character): {:?}", + s + ); if let Some(ref mut dp) = dec_point { - if *dp == 2 { continue; } // ignore following digits + if *dp == 2 { + continue; + } // ignore following digits *dp += 1; } let d = b - b'0'; @@ -138,7 +177,10 @@ impl DnsTextData for LOC { Ok(field) => { let f_altitude = trim_unit_m(field).parse::()?; let altitude = (f_altitude * 100.0 + 10000000.0).round() as i64; - failure::ensure!(altitude > 0 && (altitude as u32) as i64 == altitude, "altitude out of range"); + failure::ensure!( + altitude > 0 && (altitude as u32) as i64 == altitude, + "altitude out of range" + ); altitude as u32 }, // standard requires the field, but the example parser doesn't.. @@ -160,7 +202,7 @@ impl DnsTextData for LOC { Err(_) => 0x13, // 1e3 cm = 10m */ }; - Ok(LOC::Version0(LOC0{ + Ok(LOC::Version0(LOC0 { size, horizontal_precision, vertical_precision, @@ -178,10 +220,14 @@ impl DnsTextData for LOC { const MAX_LAT_OFFSET: u32 = 3600_000 * 180; const MAX_LON_OFFSET: u32 = 3600_000 * 180; const LATLON_MID: u32 = 0x8000_0000; - if this.latitude < LATLON_MID - MAX_LAT_OFFSET || this.latitude > LATLON_MID + MAX_LAT_OFFSET { + if this.latitude < LATLON_MID - MAX_LAT_OFFSET + || this.latitude > LATLON_MID + MAX_LAT_OFFSET + { return Err(fmt::Error); } - if this.longitude < LATLON_MID - MAX_LON_OFFSET || this.longitude > LATLON_MID + MAX_LON_OFFSET { + if this.longitude < LATLON_MID - MAX_LON_OFFSET + || this.longitude > LATLON_MID + MAX_LON_OFFSET + { return Err(fmt::Error); } @@ -190,7 +236,10 @@ impl DnsTextData for LOC { // if the leading digit is 0, the exponent must be 0 too. (v > 0x00 && v < 0x10) || (v >> 4) > 9 || (v & 0xf) > 9 } - if is_invalid_prec(this.size) || is_invalid_prec(this.horizontal_precision) || is_invalid_prec(this.vertical_precision) { + if is_invalid_prec(this.size) + || is_invalid_prec(this.horizontal_precision) + || is_invalid_prec(this.vertical_precision) + { return Err(fmt::Error); } @@ -227,7 +276,8 @@ impl DnsTextData for LOC { write!(f, "{:0) -> Result { - let prefix: u8 = DnsPacketData::deserialize(data) - .context("failed parsing field A6::prefix")?; + let prefix: u8 = + DnsPacketData::deserialize(data).context("failed parsing field A6::prefix")?; failure::ensure!(prefix <= 128, "invalid A6::prefix {}", prefix); let suffix_offset = (prefix / 8) as usize; debug_assert!(suffix_offset <= 16); @@ -310,15 +360,15 @@ impl DnsPacketData for A6 { impl DnsTextData for A6 { fn dns_parse(context: &DnsTextContext, data: &mut &str) -> Result { - let prefix: u8 = DnsTextData::dns_parse(context, data) - .context("failed parsing field A6::prefix")?; + let prefix: u8 = + DnsTextData::dns_parse(context, data).context("failed parsing field A6::prefix")?; failure::ensure!(prefix <= 128, "invalid A6::prefix {}", prefix); let suffix_offset = (prefix / 8) as usize; debug_assert!(suffix_offset <= 16); - let suffix: Ipv6Addr = DnsTextData::dns_parse(context, data) - .context("failed parsing field A6::suffix")?; + let suffix: Ipv6Addr = + DnsTextData::dns_parse(context, data).context("failed parsing field A6::suffix")?; // clear prefix bits let mut suffix = suffix.octets(); @@ -332,8 +382,10 @@ impl DnsTextData for A6 { let suffix = Ipv6Addr::from(suffix); let prefix_name = if !data.is_empty() { - Some(DnsTextData::dns_parse(context, data) - .context("failed parsing field A6::prefix_name")?) + Some( + DnsTextData::dns_parse(context, data) + .context("failed parsing field A6::prefix_name")?, + ) } else { None }; @@ -376,22 +428,34 @@ impl DnsPacketData for APL { fn deserialize(data: &mut ::std::io::Cursor) -> Result { let mut items = Vec::new(); while data.has_remaining() { - let family: u16 = DnsPacketData::deserialize(data) - .context("failed parsing APL::ADDRESSFAMILY")?; - failure::ensure!(family == 1 || family == 2, "unknown APL::ADDRESSFAMILY {}", family); - let prefix: u8 = DnsPacketData::deserialize(data) - .context("failed parsing field APL::PREFIX")?; - let afd_length: u8 = DnsPacketData::deserialize(data) - .context("failed parsing field APL::AFDLENGTH")?; + let family: u16 = + DnsPacketData::deserialize(data).context("failed parsing APL::ADDRESSFAMILY")?; + failure::ensure!( + family == 1 || family == 2, + "unknown APL::ADDRESSFAMILY {}", + family + ); + let prefix: u8 = + DnsPacketData::deserialize(data).context("failed parsing field APL::PREFIX")?; + let afd_length: u8 = + DnsPacketData::deserialize(data).context("failed parsing field APL::AFDLENGTH")?; let negation = 0 != (afd_length & 0x80); let afd_length = afd_length & 0x7f; let data = get_blob(data, afd_length as usize)?; - failure::ensure!(!data.ends_with(b"\0"), "APL::AFDPART ends with trailing zero"); + failure::ensure!( + !data.ends_with(b"\0"), + "APL::AFDPART ends with trailing zero" + ); let address = if family == 1 { failure::ensure!(prefix <= 32, "invalid APL::prefix {} for IPv4", prefix); - failure::ensure!((afd_length as u32) * 8 < (prefix as u32) + 7, "APL::AFDPART too long {} for prefix {}", afd_length, prefix); + failure::ensure!( + (afd_length as u32) * 8 < (prefix as u32) + 7, + "APL::AFDPART too long {} for prefix {}", + afd_length, + prefix + ); assert!(afd_length <= 4); let mut buf = [0u8; 4]; buf[..data.len()].copy_from_slice(&data); @@ -399,7 +463,12 @@ impl DnsPacketData for APL { } else { assert!(family == 2); failure::ensure!(prefix <= 128, "invalid APL::prefix {} for IPv6", prefix); - failure::ensure!((afd_length as u32) * 8 < (prefix as u32) + 7, "AFD::AFDPART too long {} for prefix {}", afd_length, prefix); + failure::ensure!( + (afd_length as u32) * 8 < (prefix as u32) + 7, + "AFD::AFDPART too long {} for prefix {}", + afd_length, + prefix + ); assert!(afd_length <= 16); let mut buf = [0u8; 16]; buf[..data.len()].copy_from_slice(&data); @@ -408,10 +477,7 @@ impl DnsPacketData for APL { use cidr::Cidr; let prefix = cidr::IpCidr::new(address, prefix)?; - items.push(AplItem { - prefix, - negation, - }) + items.push(AplItem { prefix, negation }) } Ok(APL { items }) } @@ -427,13 +493,17 @@ impl DnsPacketData for APL { match &item.prefix { cidr::IpCidr::V4(p) => { let addr = p.first_address().octets(); - while l > 0 && addr[l as usize -1] == 0 { l -= 1; } + while l > 0 && addr[l as usize - 1] == 0 { + l -= 1; + } packet.put_u8(l | negation_flag); packet.extend_from_slice(&addr[..l as usize]); }, cidr::IpCidr::V6(p) => { let addr = p.first_address().octets(); - while l > 0 && addr[l as usize -1] == 0 { l -= 1; } + while l > 0 && addr[l as usize - 1] == 0 { + l -= 1; + } packet.put_u8(l | negation_flag); packet.extend_from_slice(&addr[..l as usize]); }, @@ -453,7 +523,7 @@ impl DnsTextData for APL { (false, item) }; let (afi, prefix) = match content.find(':') { - Some(colon) => (&content[..colon], &content[colon+1..]), + Some(colon) => (&content[..colon], &content[colon + 1..]), None => failure::bail!("no colon in APL item: {:?}", item), }; let afi = afi.parse::()?; @@ -462,10 +532,7 @@ impl DnsTextData for APL { 2 => prefix.parse::()?.into(), _ => failure::bail!("Unknown address family {} in item: {:?}", afi, item), }; - items.push(AplItem { - prefix, - negation, - }); + items.push(AplItem { prefix, negation }); } *data = ""; Ok(APL { items }) @@ -482,7 +549,6 @@ impl DnsTextData for APL { } } - #[derive(Clone, PartialEq, Eq, Debug)] pub enum IpsecKeyGateway { None, @@ -494,19 +560,19 @@ pub enum IpsecKeyGateway { #[derive(Clone, PartialEq, Eq, Debug, RRData)] #[RRClass(ANY)] pub enum IPSECKEY { - Known{ + Known { precedence: u8, algorithm: u8, gateway: IpsecKeyGateway, public_key: Base64RemainingBlob, }, - UnknownGateway{ + UnknownGateway { precedence: u8, gateway_type: u8, algorithm: u8, // length of gateway is unknown, can't split gateway and public key remaining: Bytes, - } + }, } impl DnsPacketData for IPSECKEY { @@ -519,14 +585,16 @@ impl DnsPacketData for IPSECKEY { 1 => IpsecKeyGateway::Ipv4(Ipv4Addr::deserialize(data)?), 2 => IpsecKeyGateway::Ipv6(Ipv6Addr::deserialize(data)?), 3 => IpsecKeyGateway::Name(DnsName::deserialize(data)?), - _ => return Ok(IPSECKEY::UnknownGateway{ - precedence, - gateway_type, - algorithm, - remaining: remaining_bytes(data), - }), + _ => { + return Ok(IPSECKEY::UnknownGateway { + precedence, + gateway_type, + algorithm, + remaining: remaining_bytes(data), + }) + }, }; - Ok(IPSECKEY::Known{ + Ok(IPSECKEY::Known { precedence, algorithm, gateway, @@ -536,7 +604,12 @@ impl DnsPacketData for IPSECKEY { fn serialize(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { match *self { - IPSECKEY::Known{precedence, algorithm, ref gateway, ref public_key} => { + IPSECKEY::Known { + precedence, + algorithm, + ref gateway, + ref public_key, + } => { packet.reserve(3); packet.put_u8(precedence); let gateway_type: u8 = match *gateway { @@ -555,13 +628,18 @@ impl DnsPacketData for IPSECKEY { }; public_key.serialize(context, packet)?; }, - IPSECKEY::UnknownGateway{precedence, gateway_type, algorithm, ref remaining} => { + IPSECKEY::UnknownGateway { + precedence, + gateway_type, + algorithm, + ref remaining, + } => { packet.reserve(3 + remaining.len()); packet.put_u8(precedence); packet.put_u8(gateway_type); packet.put_u8(algorithm); packet.put_slice(remaining); - } + }, } Ok(()) } @@ -579,7 +657,7 @@ impl DnsTextData for IPSECKEY { 3 => IpsecKeyGateway::Name(DnsName::dns_parse(context, data)?), _ => failure::bail!("unknown gateway type {} for IPSECKEY", gateway_type), }; - Ok(IPSECKEY::Known{ + Ok(IPSECKEY::Known { precedence, algorithm, gateway, @@ -589,7 +667,12 @@ impl DnsTextData for IPSECKEY { fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { match *self { - IPSECKEY::Known{precedence, algorithm, ref gateway, ref public_key} => { + IPSECKEY::Known { + precedence, + algorithm, + ref gateway, + ref public_key, + } => { let gateway_type: u8 = match *gateway { IpsecKeyGateway::None => 0, IpsecKeyGateway::Ipv4(_) => 1, @@ -606,7 +689,7 @@ impl DnsTextData for IPSECKEY { public_key.dns_format(f)?; Ok(()) }, - IPSECKEY::UnknownGateway{..} => Err(fmt::Error), + IPSECKEY::UnknownGateway { .. } => Err(fmt::Error), } } } diff --git a/lib/dnsbox-base/src/ser/mod.rs b/lib/dnsbox-base/src/ser/mod.rs index a072ee6..adb6a29 100644 --- a/lib/dnsbox-base/src/ser/mod.rs +++ b/lib/dnsbox-base/src/ser/mod.rs @@ -1,7 +1,7 @@ -mod rrdata; pub mod packet; +mod rrdata; pub mod text; pub use self::packet::DnsPacketWriteContext; -pub use self::rrdata::{RRDataPacket, RRDataText, RRData, StaticRRData}; +pub use self::rrdata::{RRData, RRDataPacket, RRDataText, StaticRRData}; pub use self::text::DnsTextContext; diff --git a/lib/dnsbox-base/src/ser/packet/mod.rs b/lib/dnsbox-base/src/ser/packet/mod.rs index 0c29f37..1967af8 100644 --- a/lib/dnsbox-base/src/ser/packet/mod.rs +++ b/lib/dnsbox-base/src/ser/packet/mod.rs @@ -1,5 +1,5 @@ -use bytes::{Bytes, Buf, BufMut}; use crate::errors::*; +use bytes::{Buf, BufMut, Bytes}; use std::io::Cursor; mod std_impls; @@ -20,7 +20,11 @@ where { let mut c = Cursor::new(data); let result = parser(&mut c)?; - failure::ensure!(!c.has_remaining(), "data remaining: {} bytes", c.remaining()); + failure::ensure!( + !c.has_remaining(), + "data remaining: {} bytes", + c.remaining() + ); Ok(result) } @@ -47,7 +51,10 @@ pub fn short_blob(data: &mut Cursor) -> Result { } pub fn write_short_blob(data: &[u8], packet: &mut Vec) -> Result<()> { - failure::ensure!(data.len() < 256, "short blob must be at most 255 bytes long"); + failure::ensure!( + data.len() < 256, + "short blob must be at most 255 bytes long" + ); packet.reserve(data.len() + 1); packet.put_u8(data.len() as u8); packet.put_slice(data); diff --git a/lib/dnsbox-base/src/ser/packet/std_impls.rs b/lib/dnsbox-base/src/ser/packet/std_impls.rs index 1a143fe..d2936f1 100644 --- a/lib/dnsbox-base/src/ser/packet/std_impls.rs +++ b/lib/dnsbox-base/src/ser/packet/std_impls.rs @@ -1,6 +1,6 @@ -use bytes::{Bytes, Buf, BufMut}; use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; +use bytes::{Buf, BufMut, Bytes}; use std::io::{Cursor, Read}; use std::mem::size_of; use std::net::{Ipv4Addr, Ipv6Addr}; @@ -101,7 +101,7 @@ mod tests { use crate::errors::*; fn deserialize(data: &'static [u8]) -> Result { - use bytes::{Bytes,Buf}; + use bytes::{Buf, Bytes}; use std::io::Cursor; let mut c = Cursor::new(Bytes::from_static(data)); let result = T::deserialize(&mut c)?; diff --git a/lib/dnsbox-base/src/ser/packet/write.rs b/lib/dnsbox-base/src/ser/packet/write.rs index 2e784c3..e75ac43 100644 --- a/lib/dnsbox-base/src/ser/packet/write.rs +++ b/lib/dnsbox-base/src/ser/packet/write.rs @@ -1,6 +1,6 @@ -use bytes::{BufMut}; +use crate::common_types::name::{DnsCompressedName, DnsLabelRef, DnsName}; use crate::errors::*; -use crate::common_types::name::{DnsName, DnsCompressedName, DnsLabelRef}; +use bytes::BufMut; // only points to uncompressed labels; if a label of a name is stored, // all following labels must be stored too, even if their pos >= 0x4000. @@ -8,7 +8,7 @@ use crate::common_types::name::{DnsName, DnsCompressedName, DnsLabelRef}; // the entries are ordered by pos. #[derive(Clone, Copy, Debug, Default)] struct LabelEntry { - pos: usize, // serialized at position in packet + pos: usize, // serialized at position in packet next_entry: usize, // offset in labels vector; points to itself for TLD } @@ -16,7 +16,7 @@ impl LabelEntry { fn label_ref<'a>(&self, packet: &'a Vec) -> DnsLabelRef<'a> { let p = self.pos as usize; let len = packet[p] as usize; - DnsLabelRef::new(&packet[p+1..][..len]).unwrap() + DnsLabelRef::new(&packet[p + 1..][..len]).unwrap() } fn next(&self, labels: &Vec) -> Option { @@ -28,13 +28,19 @@ impl LabelEntry { } } - fn matches(&self, packet: &Vec, labels: &Vec, name: &DnsName, min: u8) -> Option { + fn matches( + &self, + packet: &Vec, + labels: &Vec, + name: &DnsName, + min: u8, + ) -> Option { 'outer: for i in 0..min { if name.label_ref(i) != self.label_ref(packet) { continue; } let mut l = *self; - for j in i+1..name.label_count() { + for j in i + 1..name.label_count() { l = match l.next(labels) { None => continue 'outer, Some(l) => l, @@ -86,7 +92,12 @@ fn write_canonical_name(packet: &mut Vec, name: &DnsName) { packet.put_u8(0); } -fn write_label_remember(packet: &mut Vec, labels: &mut Vec, label: DnsLabelRef, next_entry: usize) { +fn write_label_remember( + packet: &mut Vec, + labels: &mut Vec, + label: DnsLabelRef, + next_entry: usize, +) { labels.push(LabelEntry { pos: packet.len(), next_entry: next_entry, @@ -110,7 +121,6 @@ impl Default for LabelWriteMethod { #[derive(Clone, Debug, Default)] pub struct DnsPacketWriteContext { labels: LabelWriteMethod, - } impl DnsPacketWriteContext { @@ -137,7 +147,11 @@ impl DnsPacketWriteContext { self.labels = LabelWriteMethod::Canonical; } - pub(crate) fn write_uncompressed_name(&mut self, packet: &mut Vec, name: &DnsName) -> Result<()> { + pub(crate) fn write_uncompressed_name( + &mut self, + packet: &mut Vec, + name: &DnsName, + ) -> Result<()> { // for now we don't remember labels of these names. // // if we did: would we want to check whether a suffix is already @@ -147,7 +161,11 @@ impl DnsPacketWriteContext { Ok(()) } - pub(crate) fn write_canonical_name(&mut self, packet: &mut Vec, name: &DnsName) -> Result<()> { + pub(crate) fn write_canonical_name( + &mut self, + packet: &mut Vec, + name: &DnsName, + ) -> Result<()> { match self.labels { LabelWriteMethod::Uncompressed | LabelWriteMethod::Compressed(_) => { // uncompressed @@ -157,10 +175,14 @@ impl DnsPacketWriteContext { write_canonical_name(packet, name); }, } - return Ok(()) + return Ok(()); } - pub(crate) fn write_compressed_name(&mut self, packet: &mut Vec, name: &DnsCompressedName) -> Result<()> { + pub(crate) fn write_compressed_name( + &mut self, + packet: &mut Vec, + name: &DnsCompressedName, + ) -> Result<()> { // for DNSSEC we need to write it canonical if name.is_root() { write_name(packet, name); @@ -175,7 +197,7 @@ impl DnsPacketWriteContext { LabelWriteMethod::Compressed(ref mut labels) => labels, LabelWriteMethod::Canonical => { write_canonical_name(packet, name); - return Ok(()) + return Ok(()); }, }; @@ -183,7 +205,9 @@ impl DnsPacketWriteContext { let mut best_match_len = name.label_count(); for (e_ndx, e) in (labels as &Vec).into_iter().enumerate() { - if e.pos >= 0x4000 { break; } // this and following labels can't be used for compression + if e.pos >= 0x4000 { + break; + } // this and following labels can't be used for compression if let Some(l) = e.matches(packet, labels, name, best_match_len) { debug_assert!(l < best_match_len); best_match_len = l; @@ -207,7 +231,12 @@ impl DnsPacketWriteContext { write_label_remember(packet, labels, name.label_ref(i), n); } // the next label following is at e_ndx - write_label_remember(packet, labels, name.label_ref(best_match_len-1), e_ndx); + write_label_remember( + packet, + labels, + name.label_ref(best_match_len - 1), + e_ndx, + ); } else { // no need to remember, can't be used for compression for i in 0..best_match_len { @@ -232,7 +261,7 @@ impl DnsPacketWriteContext { } // the next label is the TLD let n = labels.len(); // point to itself - write_label_remember(packet, labels, name.label_ref(best_match_len-1), n); + write_label_remember(packet, labels, name.label_ref(best_match_len - 1), n); // terminate name packet.reserve(1); packet.put_u8(0); @@ -240,9 +269,9 @@ impl DnsPacketWriteContext { // no need to remember, can't be used for compression write_name(packet, name); } - } + }, } Ok(()) } -} \ No newline at end of file +} diff --git a/lib/dnsbox-base/src/ser/rrdata.rs b/lib/dnsbox-base/src/ser/rrdata.rs index 3b16e39..a45325e 100644 --- a/lib/dnsbox-base/src/ser/rrdata.rs +++ b/lib/dnsbox-base/src/ser/rrdata.rs @@ -1,9 +1,9 @@ -use bytes::Bytes; -use crate::common_types::{Class, Type, classes}; +use crate::common_types::{classes, Class, Type}; use crate::errors::*; use crate::records::UnknownRecord; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext}; +use crate::ser::text::{DnsTextContext, DnsTextData, DnsTextFormatter}; +use bytes::Bytes; use std::any::Any; use std::borrow::Cow; use std::fmt; @@ -12,21 +12,39 @@ use std::io::Cursor; pub use dnsbox_derive::RRData; pub trait RRDataPacket { - fn deserialize_rr_data(ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor) -> Result + fn deserialize_rr_data( + ttl: u32, + rr_class: Class, + rr_type: Type, + data: &mut Cursor, + ) -> Result where - Self: Sized, - ; + Self: Sized; fn rr_type(&self) -> Type; - fn serialize_rr_data(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()>; + fn serialize_rr_data( + &self, + context: &mut DnsPacketWriteContext, + packet: &mut Vec, + ) -> Result<()>; } impl RRDataPacket for T { - fn deserialize_rr_data(_ttl: u32, rr_class: Class, rr_type: Type, data: &mut Cursor) -> Result { + fn deserialize_rr_data( + _ttl: u32, + rr_class: Class, + rr_type: Type, + data: &mut Cursor, + ) -> Result { failure::ensure!(rr_type == T::TYPE, "type mismatch"); if T::CLASS != classes::ANY { - failure::ensure!(rr_class == T::CLASS, "class mismatch: got {}, need {}", rr_class, T::CLASS); + failure::ensure!( + rr_class == T::CLASS, + "class mismatch: got {}, need {}", + rr_class, + T::CLASS + ); } T::deserialize(data) } @@ -35,7 +53,11 @@ impl RRDataPacket for T { T::TYPE } - fn serialize_rr_data(&self, context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { + fn serialize_rr_data( + &self, + context: &mut DnsPacketWriteContext, + packet: &mut Vec, + ) -> Result<()> { self.serialize(context, packet) } } @@ -43,8 +65,7 @@ impl RRDataPacket for T { pub trait RRDataText { fn dns_parse_rr_data(context: &DnsTextContext, data: &mut &str) -> Result where - Self: Sized, - ; + Self: Sized; // format might fail if there is no (known) text representation. fn dns_format_rr_data(&self, f: &mut DnsTextFormatter) -> fmt::Result; @@ -58,9 +79,16 @@ impl RRDataText for T { Self: Sized, { failure::ensure!(context.record_type() == Some(T::TYPE), "type mismatch"); - let rr_class = context.zone_class().expect("require zone CLASS to parse record"); + let rr_class = context + .zone_class() + .expect("require zone CLASS to parse record"); if T::CLASS != classes::ANY { - failure::ensure!(rr_class == T::CLASS, "class mismatch: got {}, need {}", rr_class, T::CLASS); + failure::ensure!( + rr_class == T::CLASS, + "class mismatch: got {}, need {}", + rr_class, + T::CLASS + ); } failure::ensure!(context.last_ttl().is_some(), "require TTL to parse record"); T::dns_parse(context, data) @@ -84,9 +112,7 @@ pub trait RRData: RRDataPacket + RRDataText + fmt::Debug + 'static { fn text(&self) -> Result<(String, String)> { let mut buf = String::new(); match self.dns_format_rr_data(&mut DnsTextFormatter::new(&mut buf)) { - Ok(()) => { - return Ok((self.rr_type_txt().into(), buf)) - }, + Ok(()) => return Ok((self.rr_type_txt().into(), buf)), Err(_) => (), } let mut raw = Vec::new(); @@ -94,7 +120,8 @@ pub trait RRData: RRDataPacket + RRDataText + fmt::Debug + 'static { let ur = UnknownRecord::new(self.rr_type(), raw.into()); // formatting UnknownRecord should not fail buf.clear(); - ur.dns_format_rr_data(&mut DnsTextFormatter::new(&mut buf)).expect("formatting UnknownRecord must not fail"); + ur.dns_format_rr_data(&mut DnsTextFormatter::new(&mut buf)) + .expect("formatting UnknownRecord must not fail"); Ok((ur.rr_type_txt().into(), buf)) } } diff --git a/lib/dnsbox-base/src/ser/text/mod.rs b/lib/dnsbox-base/src/ser/text/mod.rs index 6eb69e5..3357a06 100644 --- a/lib/dnsbox-base/src/ser/text/mod.rs +++ b/lib/dnsbox-base/src/ser/text/mod.rs @@ -1,8 +1,8 @@ use crate::common_types; use std::fmt; -mod std_impls; pub mod quoted; +mod std_impls; pub use dnsbox_derive::DnsTextData; @@ -12,7 +12,9 @@ pub fn skip_whitespace(data: &mut &str) { pub fn next_field<'a>(data: &mut &'a str) -> crate::errors::Result<&'a str> { *data = (*data).trim_start(); - if data.is_empty() { failure::bail!("missing field"); } + if data.is_empty() { + failure::bail!("missing field"); + } match data.find(char::is_whitespace) { None => { let result = *data; @@ -29,7 +31,9 @@ pub fn next_field<'a>(data: &mut &'a str) -> crate::errors::Result<&'a str> { pub fn next_quoted_field(data: &mut &str) -> crate::errors::Result> { *data = (*data).trim_start(); - if data.is_empty() { failure::bail!("missing field"); } + if data.is_empty() { + failure::bail!("missing field"); + } let result = quoted::UnquoteIterator::new(data).collect::, _>>()?; Ok(result) @@ -91,7 +95,7 @@ impl<'a> DnsTextFormatter<'a> { pub fn format_field<'b>(&'b mut self) -> Result, fmt::Error> { self.next_field()?; - Ok(DnsTextFormatField{ inner: self }) + Ok(DnsTextFormatField { inner: self }) } pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { @@ -208,8 +212,7 @@ impl DnsTextContext { pub trait DnsTextData { fn dns_parse(context: &DnsTextContext, data: &mut &str) -> crate::errors::Result where - Self: Sized, - ; + Self: Sized; // format might fail if there is no (known) text representation. fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result; } @@ -221,7 +224,11 @@ where let mut data = data; let result = parser(&mut data)?; let data = data.trim(); - failure::ensure!(data.is_empty(), "didn't parse complete text, remaining: {:?}", data); + failure::ensure!( + data.is_empty(), + "didn't parse complete text, remaining: {:?}", + data + ); Ok(result) } diff --git a/lib/dnsbox-base/src/ser/text/quoted.rs b/lib/dnsbox-base/src/ser/text/quoted.rs index bdab294..761b86f 100644 --- a/lib/dnsbox-base/src/ser/text/quoted.rs +++ b/lib/dnsbox-base/src/ser/text/quoted.rs @@ -15,19 +15,19 @@ impl ::std::ops::Deref for EncodedByte { pub struct EncodeIterator<'a> { encode_whitespace: bool, - data: &'a [u8] + data: &'a [u8], } impl<'a> EncodeIterator<'a> { pub fn new_quoted(value: &'a [u8]) -> Self { - EncodeIterator{ + EncodeIterator { encode_whitespace: false, data: value, } } pub fn new_encode_whitespace(value: &'a [u8]) -> Self { - EncodeIterator{ + EncodeIterator { encode_whitespace: true, data: value, } @@ -38,7 +38,9 @@ impl<'a> Iterator for EncodeIterator<'a> { type Item = EncodedByte; fn next(&mut self) -> Option { - if self.data.is_empty() { return None; } + if self.data.is_empty() { + return None; + } let b = self.data[0]; self.data = &self.data[1..]; if b < 32 || b > 127 || (self.encode_whitespace && is_ascii_whitespace(b)) { @@ -46,18 +48,18 @@ impl<'a> Iterator for EncodeIterator<'a> { let d1 = b / 100; let d2 = (b / 10) % 10; let d3 = b % 10; - Some(EncodedByte{ + Some(EncodedByte { storage: [b'\\', b'0' + d1, b'0' + d2, b'0' + d3], used: 4, }) } else if b == b'"' || b == b'\\' { // `\c` - Some(EncodedByte{ + Some(EncodedByte { storage: [b'\\', b, 0, 0], used: 2, }) } else { - Some(EncodedByte{ + Some(EncodedByte { storage: [b, 0, 0, 0], used: 1, }) @@ -74,7 +76,11 @@ pub struct UnquoteError { impl fmt::Display for UnquoteError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unquote error at position {} in {:?}: {}", self.position, self.data, self.msg) + write!( + f, + "unquote error at position {} in {:?}: {}", + self.position, self.data, self.msg + ) } } @@ -98,7 +104,7 @@ impl<'a, 'b: 'a> UnquoteIterator<'a, 'b> { } fn err(&mut self, msg: &'static str) -> Option> { - Some(Err(UnquoteError{ + Some(Err(UnquoteError { data: (*self.data).into(), position: self.pos, msg: msg, @@ -123,7 +129,9 @@ impl<'a, 'b: 'a> Iterator for UnquoteIterator<'a, 'b> { fn next(&mut self) -> Option { let raw = self.data.as_bytes(); - if raw.is_empty() { return self.err("empty input"); } + if raw.is_empty() { + return self.err("empty input"); + } if 0 == self.pos { // check for starting quote: @@ -144,12 +152,12 @@ impl<'a, 'b: 'a> Iterator for UnquoteIterator<'a, 'b> { if raw[self.pos] == b'"' { if self.quoted { // either followed by end-of-string or a whitespace - if self.pos+1 < raw.len() && !is_ascii_whitespace(raw[self.pos+1]) { + if self.pos + 1 < raw.len() && !is_ascii_whitespace(raw[self.pos + 1]) { return self.err("quote in the middle of quoted string"); } // eat terminating quote // pos+1 is obviously a good utf-8 boundary - *self.data = self.data[self.pos+1..].trim_start(); + *self.data = self.data[self.pos + 1..].trim_start(); return None; } else { return self.err("quote in the middle of unquoted string"); @@ -159,9 +167,11 @@ impl<'a, 'b: 'a> Iterator for UnquoteIterator<'a, 'b> { *self.data = self.data[self.pos..].trim_start(); return None; } else if raw[self.pos] == b'\\' { - if self.pos + 1 >= raw.len() { return self.err("unexpected end of string after backslash"); } - if raw[self.pos+1] < b'0' || raw[self.pos+1] > b'9' { - let result = raw[self.pos+1]; + if self.pos + 1 >= raw.len() { + return self.err("unexpected end of string after backslash"); + } + if raw[self.pos + 1] < b'0' || raw[self.pos + 1] > b'9' { + let result = raw[self.pos + 1]; if !self.quoted && is_ascii_whitespace(result) { return self.err("(escaped) whitespace not allowed in unquoted field"); } @@ -169,16 +179,24 @@ impl<'a, 'b: 'a> Iterator for UnquoteIterator<'a, 'b> { return Some(Ok(result)); } // otherwise require 3 decimal digits - if self.pos + 3 >= raw.len() { return self.err("unexpected end of string after backslash with decimal"); } + if self.pos + 3 >= raw.len() { + return self.err("unexpected end of string after backslash with decimal"); + } // raw[self.pos+1] already checked for digit above - if raw[self.pos+2] < b'0' || raw[self.pos+2] > b'9' || raw[self.pos+3] < b'0' || raw[self.pos+3] > b'9' { + if raw[self.pos + 2] < b'0' + || raw[self.pos + 2] > b'9' + || raw[self.pos + 3] < b'0' + || raw[self.pos + 3] > b'9' + { return self.err("expecting 3 digits after backslash with decimal"); } - let d1 = raw[self.pos+1] - b'0'; - let d2 = raw[self.pos+2] - b'0'; - let d3 = raw[self.pos+3] - b'0'; + let d1 = raw[self.pos + 1] - b'0'; + let d2 = raw[self.pos + 2] - b'0'; + let d3 = raw[self.pos + 3] - b'0'; let val = (d1 as u32 * 100) + (d2 as u32 * 10) + (d3 as u32); - if val > 255 { return self.err("invalid decimal escape"); } + if val > 255 { + return self.err("invalid decimal escape"); + } self.pos += 4; Some(Ok(val as u8)) } else { @@ -194,17 +212,11 @@ mod tests { use crate::ser::text::{next_quoted_field, quote}; fn check_quote(data: &[u8], quoted: &str) { - assert_eq!( - quote(data), - quoted - ); + assert_eq!(quote(data), quoted); } fn check_unquote(mut input: &str, data: &[u8]) { - assert_eq!( - next_quoted_field(&mut input).unwrap(), - data - ); + assert_eq!(next_quoted_field(&mut input).unwrap(), data); assert!(input.is_empty()); } diff --git a/lib/dnsbox-base/src/ser/text/std_impls.rs b/lib/dnsbox-base/src/ser/text/std_impls.rs index 9ffdd38..db948a9 100644 --- a/lib/dnsbox-base/src/ser/text/std_impls.rs +++ b/lib/dnsbox-base/src/ser/text/std_impls.rs @@ -1,6 +1,6 @@ +use crate::ser::text::{next_field, DnsTextContext, DnsTextData, DnsTextFormatter}; use std::fmt; use std::net::{Ipv4Addr, Ipv6Addr}; -use crate::ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field}; impl DnsTextData for () { fn dns_parse(_context: &DnsTextContext, _data: &mut &str) -> crate::errors::Result { @@ -92,30 +92,22 @@ mod tests { fn test_ipv6() { assert_eq!( deserialize::("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210").unwrap(), - Ipv6Addr::new( - 0xfedc, 0xba98, 0x7654, 0x3210, 0xfedc, 0xba98, 0x7654, 0x3210 - ) + Ipv6Addr::new(0xfedc, 0xba98, 0x7654, 0x3210, 0xfedc, 0xba98, 0x7654, 0x3210) ); assert_eq!( deserialize::("1080::8:800:200C:417A").unwrap(), - Ipv6Addr::new( - 0x1080, 0, 0, 0, 0x8, 0x800, 0x200c, 0x417a - ) + Ipv6Addr::new(0x1080, 0, 0, 0, 0x8, 0x800, 0x200c, 0x417a) ); assert_eq!( deserialize::("::13.1.68.3").unwrap(), - Ipv6Addr::new( - 0, 0, 0, 0, 0, 0, 0x0d01, 0x4403 - ) + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x0d01, 0x4403) ); assert_eq!( deserialize::("::FFFF:129.144.52.38").unwrap(), - Ipv6Addr::new( - 0, 0, 0, 0, 0, 0xffff, 0x8190, 0x3426 - ) + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x8190, 0x3426) ); } diff --git a/lib/dnsbox-base/src/unsafe_ops/mod.rs b/lib/dnsbox-base/src/unsafe_ops/mod.rs index 74b4f87..67e2e28 100644 --- a/lib/dnsbox-base/src/unsafe_ops/mod.rs +++ b/lib/dnsbox-base/src/unsafe_ops/mod.rs @@ -1,8 +1,6 @@ #[cfg(not(feature = "no-unsafe"))] pub fn from_utf8_unchecked(v: &[u8]) -> &str { - unsafe { - ::std::str::from_utf8_unchecked(v) - } + unsafe { ::std::str::from_utf8_unchecked(v) } } #[cfg(feature = "no-unsafe")] diff --git a/lib/dnsbox-derive/src/dns_packet_data.rs b/lib/dnsbox-derive/src/dns_packet_data.rs index 02754f4..81faaa0 100644 --- a/lib/dnsbox-derive/src/dns_packet_data.rs +++ b/lib/dnsbox-derive/src/dns_packet_data.rs @@ -1,6 +1,10 @@ use proc_macro2::TokenStream; -fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, serialize_fields: TokenStream) -> TokenStream { +fn derive_impl( + s: &synstructure::Structure, + parse_fields: TokenStream, + serialize_fields: TokenStream, +) -> TokenStream { s.gen_impl(quote!{ #[allow(unused_imports)] use dnsbox_base::_failure::ResultExt; @@ -23,14 +27,14 @@ fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, serialize fn derive_unit(s: &synstructure::Structure) -> TokenStream { let name = &s.ast().ident; - derive_impl(s, quote!{#name}, quote!{}) + derive_impl(s, quote! {#name}, quote! {}) } fn derive_named(s: &synstructure::Structure, fields: &syn::FieldsNamed) -> TokenStream { let name = &s.ast().ident; - let mut parse_fields = quote!{}; - let mut serialize_fields = quote!{}; + let mut parse_fields = quote! {}; + let mut serialize_fields = quote! {}; for field in &fields.named { let field_name = field.ident.as_ref().unwrap(); @@ -45,37 +49,46 @@ fn derive_named(s: &synstructure::Structure, fields: &syn::FieldsNamed) -> Token }); } - derive_impl(s, quote!{#name{ #parse_fields }}, serialize_fields) + derive_impl(s, quote! {#name{ #parse_fields }}, serialize_fields) } fn derive_unnamed(s: &synstructure::Structure, fields: &syn::FieldsUnnamed) -> TokenStream { let name = &s.ast().ident; - let mut parse_fields = quote!{}; - let mut serialize_fields = quote!{}; + let mut parse_fields = quote! {}; + let mut serialize_fields = quote! {}; for field in 0..fields.unnamed.len() { let field = syn::Index::from(field); - parse_fields.extend(quote!{ + parse_fields.extend(quote! { DnsPacketData::deserialize(_data) .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), #field, e))?, }); - serialize_fields.extend(quote!{ + serialize_fields.extend(quote! { self.#field.serialize(_context, _packet) .with_context(|e| format!("failed serializing field {}::{}: {}", stringify!(#name), #field, e))?; }); } - derive_impl(s, quote!{#name(#parse_fields)}, serialize_fields) + derive_impl(s, quote! {#name(#parse_fields)}, serialize_fields) } pub fn derive(s: synstructure::Structure) -> TokenStream { let ast = s.ast(); match &ast.data { - syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Unit, .. }) => derive_unit(&s), - syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Named(fields), .. }) => derive_named(&s, fields), - syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Unnamed(fields), .. }) => derive_unnamed(&s, fields), + syn::Data::Struct(syn::DataStruct { + fields: syn::Fields::Unit, + .. + }) => derive_unit(&s), + syn::Data::Struct(syn::DataStruct { + fields: syn::Fields::Named(fields), + .. + }) => derive_named(&s, fields), + syn::Data::Struct(syn::DataStruct { + fields: syn::Fields::Unnamed(fields), + .. + }) => derive_unnamed(&s, fields), _ => panic!("Deriving DnsPacketData not supported for non struct types"), } } diff --git a/lib/dnsbox-derive/src/dns_text_data.rs b/lib/dnsbox-derive/src/dns_text_data.rs index 83f3b35..57a4221 100644 --- a/lib/dnsbox-derive/src/dns_text_data.rs +++ b/lib/dnsbox-derive/src/dns_text_data.rs @@ -1,6 +1,10 @@ use proc_macro2::TokenStream; -fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, format_fields: TokenStream) -> TokenStream { +fn derive_impl( + s: &synstructure::Structure, + parse_fields: TokenStream, + format_fields: TokenStream, +) -> TokenStream { s.gen_impl(quote!{ #[allow(unused_imports)] use dnsbox_base::_failure::ResultExt as _; @@ -23,14 +27,14 @@ fn derive_impl(s: &synstructure::Structure, parse_fields: TokenStream, format_fi fn derive_unit(s: &synstructure::Structure) -> TokenStream { let name = &s.ast().ident; - derive_impl(s, quote!{#name}, quote!{}) + derive_impl(s, quote! {#name}, quote! {}) } fn derive_named(s: &synstructure::Structure, fields: &syn::FieldsNamed) -> TokenStream { let name = &s.ast().ident; - let mut parse_fields = quote!{}; - let mut format_fields = quote!{}; + let mut parse_fields = quote! {}; + let mut format_fields = quote! {}; for field in &fields.named { let field_name = field.ident.as_ref().unwrap(); @@ -39,41 +43,50 @@ fn derive_named(s: &synstructure::Structure, fields: &syn::FieldsNamed) -> Token .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), stringify!(#field_name), e))?, }); - format_fields.extend(quote!{ + format_fields.extend(quote! { DnsTextData::dns_format(&self.#field_name, f)?; }); } - derive_impl(s, quote!{#name{ #parse_fields }}, format_fields) + derive_impl(s, quote! {#name{ #parse_fields }}, format_fields) } fn derive_unnamed(s: &synstructure::Structure, fields: &syn::FieldsUnnamed) -> TokenStream { let name = &s.ast().ident; - let mut parse_fields = quote!{}; - let mut format_fields = quote!{}; + let mut parse_fields = quote! {}; + let mut format_fields = quote! {}; for field in 0..fields.unnamed.len() { let field = syn::Index::from(field); - parse_fields.extend(quote!{ + parse_fields.extend(quote! { DnsTextData::dns_parse(_context, _data) .with_context(|e| format!("failed parsing field {}::{}: {}", stringify!(#name), #field, e))?, }); - format_fields.extend(quote!{ + format_fields.extend(quote! { DnsTextData::dns_format(&self.#field, f)?; }); } - derive_impl(s, quote!{#name(#parse_fields)}, format_fields) + derive_impl(s, quote! {#name(#parse_fields)}, format_fields) } pub fn derive(s: synstructure::Structure) -> TokenStream { let ast = s.ast(); match &ast.data { - syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Unit, .. }) => derive_unit(&s), - syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Named(fields), .. }) => derive_named(&s, fields), - syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Unnamed(fields), .. }) => derive_unnamed(&s, fields), + syn::Data::Struct(syn::DataStruct { + fields: syn::Fields::Unit, + .. + }) => derive_unit(&s), + syn::Data::Struct(syn::DataStruct { + fields: syn::Fields::Named(fields), + .. + }) => derive_named(&s, fields), + syn::Data::Struct(syn::DataStruct { + fields: syn::Fields::Unnamed(fields), + .. + }) => derive_unnamed(&s, fields), _ => panic!("Deriving DnsTextData not supported for non struct types"), } } diff --git a/lib/dnsbox-derive/src/lib.rs b/lib/dnsbox-derive/src/lib.rs index c834247..5d2f6ca 100644 --- a/lib/dnsbox-derive/src/lib.rs +++ b/lib/dnsbox-derive/src/lib.rs @@ -1,4 +1,4 @@ -#![recursion_limit="128"] +#![recursion_limit = "128"] #[macro_use] extern crate synstructure; @@ -6,11 +6,11 @@ extern crate synstructure; extern crate quote; extern crate proc_macro2; -mod rrdata; mod dns_packet_data; mod dns_text_data; mod native_enum; mod native_flags; +mod rrdata; decl_derive!([DnsPacketData] => dns_packet_data::derive); decl_derive!([DnsTextData] => dns_text_data::derive); @@ -20,19 +20,20 @@ decl_attribute!([native_flags] => native_flags::attribute_native_flags); fn attr_get_single_list_arg(attr_meta: &syn::Meta) -> proc_macro2::TokenStream { match attr_meta { - syn::Meta::Word(_) => { - panic!("{:?} attribute requires an argument", attr_meta.name()) - }, + syn::Meta::Word(_) => panic!("{:?} attribute requires an argument", attr_meta.name()), syn::Meta::List(l) => { if l.nested.len() != 1 { - panic!("{:?} attribute requires exactly one argument", attr_meta.name()); + panic!( + "{:?} attribute requires exactly one argument", + attr_meta.name() + ); } let arg = *l.nested.first().unwrap().value(); - quote!{#arg} + quote! {#arg} }, syn::Meta::NameValue(nv) => { let lit = &nv.lit; - quote!{#lit} + quote! {#lit} }, } } @@ -60,4 +61,4 @@ pub fn derive_dns_text_data(input: TokenStream) -> TokenStream { gen.parse().unwrap() } -*/ \ No newline at end of file +*/ diff --git a/lib/dnsbox-derive/src/native_enum.rs b/lib/dnsbox-derive/src/native_enum.rs index e37c603..8238ed3 100644 --- a/lib/dnsbox-derive/src/native_enum.rs +++ b/lib/dnsbox-derive/src/native_enum.rs @@ -5,7 +5,11 @@ pub fn attribute_native_enum( structure: synstructure::Structure, ) -> TokenStream { let ast = structure.ast(); - let in_attrs = ast.attrs.iter().map(|a| quote!{#a}).collect::(); + let in_attrs = ast + .attrs + .iter() + .map(|a| quote! {#a}) + .collect::(); let in_vis = &ast.vis; let name = &ast.ident; @@ -19,7 +23,10 @@ pub fn attribute_native_enum( { let variants = &enumdata.variants; - let doc_str = format!("Known enum variants of [`{}`]\n\n[`{}`]: struct.{}.html\n", name, name, name); + let doc_str = format!( + "Known enum variants of [`{}`]\n\n[`{}`]: struct.{}.html\n", + name, name, name + ); known_enum = quote! { #[doc = #doc_str] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -34,11 +41,21 @@ pub fn attribute_native_enum( let mut consts = TokenStream::new(); let mut convert = TokenStream::new(); for variant in &enumdata.variants { - let variant_attrs = variant.attrs.iter().map(|a| quote!{#a}).collect::(); + let variant_attrs = variant + .attrs + .iter() + .map(|a| quote! {#a}) + .collect::(); let disc_name = &variant.ident; - let disc = variant.discriminant.as_ref().map(|(_, d)| quote!{#d}).unwrap_or_else(|| quote!{ - #known_name::#disc_name as #native_type - }); + let disc = variant + .discriminant + .as_ref() + .map(|(_, d)| quote! {#d}) + .unwrap_or_else(|| { + quote! { + #known_name::#disc_name as #native_type + } + }); consts.extend(quote! { #variant_attrs pub const #disc_name: Self = #name(#disc); diff --git a/lib/dnsbox-derive/src/native_flags.rs b/lib/dnsbox-derive/src/native_flags.rs index f8be9bf..b0a008d 100644 --- a/lib/dnsbox-derive/src/native_flags.rs +++ b/lib/dnsbox-derive/src/native_flags.rs @@ -5,11 +5,18 @@ pub fn attribute_native_flags( structure: synstructure::Structure, ) -> TokenStream { let ast = structure.ast(); - let in_attrs = ast.attrs.iter().map(|a| quote!{#a}).collect::(); + let in_attrs = ast + .attrs + .iter() + .map(|a| quote! {#a}) + .collect::(); let in_vis = &ast.vis; let name = &ast.ident; - let hidden_impl_mod = syn::Ident::new(&format!("_{}_hidden_native_flags", name), proc_macro2::Span::call_site()); + let hidden_impl_mod = syn::Ident::new( + &format!("_{}_hidden_native_flags", name), + proc_macro2::Span::call_site(), + ); let enumdata = match &ast.data { syn::Data::Enum(de) => de, @@ -20,14 +27,22 @@ pub fn attribute_native_flags( let mut known_mask = TokenStream::new(); let mut dbg = TokenStream::new(); for variant in &enumdata.variants { - let variant_attrs = variant.attrs.iter().map(|a| quote!{#a}).collect::(); + let variant_attrs = variant + .attrs + .iter() + .map(|a| quote! {#a}) + .collect::(); let disc_name = &variant.ident; - let disc = variant.discriminant.as_ref().map(|(_, d)| d).expect("all variants need explicit bitmask discriminants"); + let disc = variant + .discriminant + .as_ref() + .map(|(_, d)| d) + .expect("all variants need explicit bitmask discriminants"); consts.extend(quote! { #variant_attrs pub const #disc_name: Flag = Flag { mask: #disc }; }); - known_mask.extend(quote!{ + known_mask.extend(quote! { | #disc }); dbg.extend(quote! { diff --git a/lib/dnsbox-derive/src/rrdata.rs b/lib/dnsbox-derive/src/rrdata.rs index dd655f9..57e8e3e 100644 --- a/lib/dnsbox-derive/src/rrdata.rs +++ b/lib/dnsbox-derive/src/rrdata.rs @@ -1,6 +1,6 @@ use crate::attr_get_single_list_arg; -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] enum StructAttribute { RRTypeName(proc_macro2::TokenStream), RRClass(proc_macro2::TokenStream), @@ -49,11 +49,12 @@ pub fn rrdata_derive(s: synstructure::Structure) -> proc_macro2::TokenStream { let name_str = name_str.unwrap_or_else(|| { let name_str = format!("{}", name); - quote!{#name_str} + quote! {#name_str} }); - let rr_class = rr_class.unwrap_or_else(|| quote!{ANY}); + let rr_class = rr_class.unwrap_or_else(|| quote! {ANY}); - let test_mod_name = syn::Ident::new(&format!("test_rr_{}", name), proc_macro2::Span::call_site()); + let test_mod_name = + syn::Ident::new(&format!("test_rr_{}", name), proc_macro2::Span::call_site()); let impl_rrdata = s.unbound_impl( quote!(::dnsbox_base::ser::RRData),