preview
Stefan Bühler 3 years ago
parent 460a8d1755
commit 9d5314d127

@ -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<Box<dyn RRData>>) {
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),

@ -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::<DnsName>().expect("invalid root hint name");
let ipv4 = ipv4.parse::<Ipv4Addr>().expect("invalid root hint ipv4 addr");
let ipv6 = ipv6.parse::<Ipv6Addr>().expect("invalid root hint ipv6 addr");
let ipv4 = ipv4
.parse::<Ipv4Addr>()
.expect("invalid root hint ipv4 addr");
let ipv6 = ipv6
.parse::<Ipv6Addr>()
.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);

@ -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<u8>) -> Result<Self> {
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<u8>) -> Result<Self> {
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<Self> {
let length_field = next_field(data)?;
let length = length_field.parse::<u16>()
let length = length_field
.parse::<u16>()
.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<Self> {
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<Self> {
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<Self> {
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))
}
}

@ -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

@ -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(())
}

@ -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;

@ -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<Self>
{
pub fn parse(context: &DnsTextContext, value: &str) -> Result<Self> {
Ok(DnsCanonicalName(DnsName::parse(context, value)?))
}
}
@ -65,8 +64,7 @@ impl<'a> IntoIterator for &'a DnsCanonicalName {
}
}
impl PartialEq<DnsName> for DnsCanonicalName
{
impl PartialEq<DnsName> for DnsCanonicalName {
fn eq(&self, rhs: &DnsName) -> bool {
let this: &DnsName = self;
this == rhs
@ -75,7 +73,7 @@ impl PartialEq<DnsName> for DnsCanonicalName
impl<T> PartialEq<T> for DnsCanonicalName
where
T: AsRef<DnsName>
T: AsRef<DnsName>,
{
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<Self> {
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<Bytes>) -> Result<Self> {
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<u8>) -> Result<()> {

@ -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<Self>
{
pub fn parse(context: &DnsTextContext, value: &str) -> Result<Self> {
Ok(DnsCompressedName(DnsName::parse(context, value)?))
}
}
@ -62,8 +61,7 @@ impl<'a> IntoIterator for &'a DnsCompressedName {
}
}
impl PartialEq<DnsName> for DnsCompressedName
{
impl PartialEq<DnsName> for DnsCompressedName {
fn eq(&self, rhs: &DnsName) -> bool {
let this: &DnsName = self;
this == rhs
@ -72,7 +70,7 @@ impl PartialEq<DnsName> for DnsCompressedName
impl<T> PartialEq<T> for DnsCompressedName
where
T: AsRef<DnsName>
T: AsRef<DnsName>,
{
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<Self> {
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<Bytes>) -> Result<Self> {
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<u8>) -> Result<()> {

@ -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<Item=DnsLabelRef<'a>>+Clone
I: IntoIterator<Item = DnsLabelRef<'a>> + 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<Item=DnsLabelRef<'a>>+Clone
I: IntoIterator<Item = DnsLabelRef<'a>> + 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<Item=DnsLabelRef<'a>>+Clone
I: IntoIterator<Item = DnsLabelRef<'a>> + Clone,
{
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
let mut i = self.labels.clone().into_iter();

@ -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<Self> {
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<DnsLabelRef<'a>> for DnsLabel {
fn from(label_ref: DnsLabelRef<'a>) -> Self {
DnsLabel{
DnsLabel {
label: Bytes::from(label_ref.label),
}
}
@ -78,7 +80,7 @@ impl<'a> PartialEq<DnsLabelRef<'a>> for DnsLabel {
}
}
impl Eq for DnsLabel{}
impl Eq for DnsLabel {}
impl PartialOrd<DnsLabel> 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<Self> {
check_label(label)?;
Ok(DnsLabelRef{label})
Ok(DnsLabelRef { label })
}
/// Access as raw bytes
@ -180,7 +182,7 @@ impl<'a> PartialEq<DnsLabel> for DnsLabelRef<'a> {
}
}
impl<'a> Eq for DnsLabelRef<'a>{}
impl<'a> Eq for DnsLabelRef<'a> {}
impl<'a, 'b> PartialOrd<DnsLabelRef<'a>> 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#"\."#)?,

@ -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,
}
},
}
}

@ -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;

@ -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<DnsName> for DnsName
{
impl PartialEq<DnsName> 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<T> PartialEq<T> for DnsName
where
T: AsRef<DnsName>
T: AsRef<DnsName>,
{
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)
}
}

@ -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<Self::Item> {
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<Self::Item> {
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)

@ -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<DnsLabelRef<'a>>>(&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<DnsLabelRef<'a>>>(&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,

@ -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<DnsName> {
let mut label_offsets = uncmpr_offsets.into_iter()
.map(LabelOffset::LabelStart)
.collect::<SmallVec<_>>();
fn deserialize_name_compressed_cont(
data: Bytes,
start_pos: usize,
uncmpr_offsets: SmallVec<[u8; 16]>,
mut total_len: usize,
mut label_len: u8,
) -> Result<DnsName> {
let mut label_offsets = uncmpr_offsets
.into_iter()
.map(LabelOffset::LabelStart)
.collect::<SmallVec<_>>();
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<Bytes>, accept_compressed: bool) -> Result<DnsName> {
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