From 50c85ce629ca6c8a4e667c5688c0ed0431d69cff Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Tue, 15 Mar 2016 16:21:24 +0100 Subject: [PATCH] Rework record creation; add generic record data. --- src/bytes.rs | 6 +- src/dig.rs | 16 ++-- src/iana/class.rs | 21 +++++ src/iana/rrtype.rs | 22 +++++ src/message.rs | 195 ++++++++++++++++++++++++++++----------- src/name.rs | 211 +++++++++++++++++++++++++++---------------- src/question.rs | 142 +++++++++-------------------- src/rdata/generic.rs | 93 +++++++++++++++++++ src/rdata/mod.rs | 2 + src/rdata/rfc1035.rs | 73 +++++++++------ src/rdata/traits.rs | 91 ++++++++++++++----- src/record.rs | 150 +++++++++--------------------- 12 files changed, 620 insertions(+), 402 deletions(-) create mode 100644 src/rdata/generic.rs diff --git a/src/bytes.rs b/src/bytes.rs index 2780f50d..40d2feed 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -6,7 +6,7 @@ use std::fmt; use std::mem; use std::ptr; use std::result; -use super::name::DomainName; +use super::name::DomainNameSlice; //------------ BytesBuf ----------------------------------------------------- @@ -66,12 +66,12 @@ pub trait BytesBuf { fn can_compress(&self) -> bool { false } /// Adds a reference to a domain name at the current position. - fn add_name_pos>(&mut self, name: N) { + fn add_name_pos>(&mut self, name: N) { let _ = name; } /// Retrieves the position for `name`, if available. - fn get_name_pos>(&self, name: N) -> Option { + fn get_name_pos>(&self, name: N) -> Option { let _ = name; None } } diff --git a/src/dig.rs b/src/dig.rs index 9be37b08..5bf4429a 100644 --- a/src/dig.rs +++ b/src/dig.rs @@ -7,7 +7,9 @@ use std::fmt; use std::io; use std::net::{SocketAddr, UdpSocket}; use std::result; +use domain::iana::{Class, RRType}; use domain::message::{self, MessageBuf, MessageBuilder, RecordSection}; +use domain::rdata::generic::CompactGenericRecordData; use domain::resolver::conf::ResolvConf; use domain::name::{self, DomainNameBuf}; @@ -83,12 +85,12 @@ impl Options { } } - fn qtype(&self) -> Result { - Ok((if self.name.is_empty() { 2 } else { 1 })) + fn qtype(&self) -> Result { + Ok((if self.name.is_empty() { RRType::NS } else { RRType::A })) } - fn qclass(&self) -> Result { - Ok((1)) + fn qclass(&self) -> Result { + Ok((Class::IN)) } fn conf(&self) -> &ResolvConf { &self.conf } @@ -224,11 +226,11 @@ fn print_result(response: MessageBuf) { } } -fn print_section(section: &mut RecordSection) { +fn print_section<'a>(section: &mut RecordSection<'a, CompactGenericRecordData<'a>>) { for record in section.iter() { let record = record.unwrap(); - println!("{}\t{}\t{}\t{}\t...", record.name(), record.ttl(), - record.rclass(), record.rtype()) + println!("{}\t{}\t{}\t{}\t{}", record.name(), record.ttl(), + record.rclass(), record.rtype(), record.rdata()) } } diff --git a/src/iana/class.rs b/src/iana/class.rs index 8c6b5e5f..e26bdbb3 100644 --- a/src/iana/class.rs +++ b/src/iana/class.rs @@ -84,3 +84,24 @@ impl fmt::Display for Class { } } } + + +impl PartialEq for Class { + fn eq(&self, other: &Class) -> bool { + self.to_int() == other.to_int() + } +} + +impl PartialEq for Class { + fn eq(&self, other: &u16) -> bool { + self.to_int() == *other + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &Class) -> bool { + *self == other.to_int() + } +} + +impl Eq for Class { } diff --git a/src/iana/rrtype.rs b/src/iana/rrtype.rs index 3e366538..59a987bf 100644 --- a/src/iana/rrtype.rs +++ b/src/iana/rrtype.rs @@ -687,3 +687,25 @@ impl fmt::Display for RRType { } } } + + +impl PartialEq for RRType { + fn eq(&self, other: &Self) -> bool { + self.to_int() == other.to_int() + } +} + +impl PartialEq for RRType { + fn eq(&self, other: &u16) -> bool { + self.to_int() == *other + } +} + +impl PartialEq for u16 { + fn eq(&self, other: &RRType) -> bool { + *self == other.to_int() + } +} + +impl Eq for RRType { } + diff --git a/src/message.rs b/src/message.rs index fe76e542..886fb6e5 100644 --- a/src/message.rs +++ b/src/message.rs @@ -5,14 +5,18 @@ use std::collections::HashMap; use std::convert; use std::error; use std::fmt; +use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::result; use super::header::{Header, HeaderCounts, FullHeader}; -use super::name::{self, DomainName, DomainNameBuf}; +use super::iana::{Class, RRType}; +use super::name::{self, DomainName, DomainNameBuf, DomainNameSlice, + CompactDomainName}; use super::bytes::{self, BytesBuf}; -use super::question::{self, BuildQuestion, WireQuestion}; -use super::record::{WireRecord, BuildRecord}; +use super::question::{self, Question}; +use super::record::Record; +use super::rdata::traits::{RecordData, CompactRecordData}; //============ Message Slice ================================================ @@ -88,7 +92,8 @@ impl<'a> QuestionSection<'a> { self } - pub fn answer(self) -> Option> { + pub fn answer>(self) + -> Option> { if self.count == 0 { Some(AnswerSection::new(self.message, self.slice)) } @@ -97,11 +102,11 @@ impl<'a> QuestionSection<'a> { } impl<'a> Iterator for QuestionSection<'a> { - type Item = Result>; + type Item = Result>>; fn next(&mut self) -> Option { if self.count == 0 { return None } - match WireQuestion::split_from(self.slice, &self.message.slice) { + match Question::split_from(self.slice, &self.message.slice) { Ok((res, slice)) => { self.count -= 1; self.slice = slice; @@ -116,15 +121,17 @@ impl<'a> Iterator for QuestionSection<'a> { //------------ RecordSection ------------------------------------------------ #[derive(Debug)] -pub struct RecordSection<'a> { +pub struct RecordSection<'a, D: CompactRecordData<'a>> { message: &'a Message, slice: &'a [u8], - count: u16 + count: u16, + phantom: PhantomData, } -impl<'a> RecordSection<'a> { +impl<'a, D: CompactRecordData<'a>> RecordSection<'a, D> { fn new(message: &'a Message, slice: &'a[u8], count: u16) -> Self { - RecordSection { message: message, slice: slice, count: count } + RecordSection { message: message, slice: slice, count: count, + phantom: PhantomData } } pub fn iter(&mut self) -> &mut Self { @@ -132,18 +139,23 @@ impl<'a> RecordSection<'a> { } } -impl<'a> Iterator for RecordSection<'a> { - type Item = Result>; +impl<'a, D: CompactRecordData<'a>> Iterator for RecordSection<'a, D> { + type Item = Result, D>>; fn next(&mut self) -> Option { - if self.count == 0 { return None } - match WireRecord::split_from(self.slice, &self.message.slice) { - Ok((res, slice)) => { - self.count -= 1; - self.slice = slice; - Some(Ok(res)) + loop { + if self.count == 0 { return None } + match Record::split_from(self.slice, &self.message.slice) { + Ok((inner, slice)) => { + self.count -= 1; + self.slice = slice; + match inner { + Some(record) => return Some(Ok(record)), + None => { } + } + } + Err(e) => return Some(Err(Error::from(e))) } - Err(e) => Some(Err(Error::from(e))) } } } @@ -152,11 +164,11 @@ impl<'a> Iterator for RecordSection<'a> { //------------ AnswerSection ------------------------------------------------ #[derive(Debug)] -pub struct AnswerSection<'a> { - inner: RecordSection<'a>, +pub struct AnswerSection<'a, D: CompactRecordData<'a>> { + inner: RecordSection<'a, D>, } -impl<'a> AnswerSection<'a> { +impl<'a, D: CompactRecordData<'a>> AnswerSection<'a, D> { fn new(message: &'a Message, slice: &'a[u8]) -> Self { AnswerSection { inner: RecordSection::new(message, slice, @@ -164,7 +176,7 @@ impl<'a> AnswerSection<'a> { } } - pub fn authority(self) -> Option> { + pub fn authority(self) -> Option> { if self.inner.count == 0 { Some(AuthoritySection::new(self.inner.message, self.inner.slice)) } @@ -172,15 +184,15 @@ impl<'a> AnswerSection<'a> { } } -impl<'a> Deref for AnswerSection<'a> { - type Target = RecordSection<'a>; +impl<'a, D: CompactRecordData<'a>> Deref for AnswerSection<'a, D> { + type Target = RecordSection<'a, D>; fn deref(&self) -> &Self::Target { &self.inner } } -impl<'a> DerefMut for AnswerSection<'a> { +impl<'a, D: CompactRecordData<'a>> DerefMut for AnswerSection<'a, D> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } @@ -190,11 +202,11 @@ impl<'a> DerefMut for AnswerSection<'a> { //------------ AuthoritySection --------------------------------------------- #[derive(Debug)] -pub struct AuthoritySection<'a> { - inner: RecordSection<'a> +pub struct AuthoritySection<'a, D: CompactRecordData<'a>> { + inner: RecordSection<'a, D> } -impl<'a> AuthoritySection<'a> { +impl<'a, D: CompactRecordData<'a>> AuthoritySection<'a, D> { fn new(message: &'a Message, slice: &'a[u8]) -> Self { AuthoritySection { inner: RecordSection::new(message, slice, @@ -202,7 +214,7 @@ impl<'a> AuthoritySection<'a> { } } - pub fn additional(self) -> Option> { + pub fn additional(self) -> Option> { if self.inner.count == 0 { Some(AdditionalSection::new(self.inner.message, self.inner.slice)) @@ -211,15 +223,15 @@ impl<'a> AuthoritySection<'a> { } } -impl<'a> Deref for AuthoritySection<'a> { - type Target = RecordSection<'a>; +impl<'a, D: CompactRecordData<'a>> Deref for AuthoritySection<'a, D> { + type Target = RecordSection<'a, D>; fn deref(&self) -> &Self::Target { &self.inner } } -impl<'a> DerefMut for AuthoritySection<'a> { +impl<'a, D: CompactRecordData<'a>> DerefMut for AuthoritySection<'a, D> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } @@ -229,11 +241,11 @@ impl<'a> DerefMut for AuthoritySection<'a> { //------------ AdditionalSection -------------------------------------------- #[derive(Debug)] -pub struct AdditionalSection<'a> { - inner: RecordSection<'a> +pub struct AdditionalSection<'a, D: CompactRecordData<'a>> { + inner: RecordSection<'a, D> } -impl<'a> AdditionalSection<'a> { +impl<'a, D: CompactRecordData<'a>> AdditionalSection<'a, D> { fn new(message: &'a Message, slice: &'a[u8]) -> Self { AdditionalSection { inner: RecordSection::new(message, slice, @@ -242,15 +254,15 @@ impl<'a> AdditionalSection<'a> { } } -impl<'a> Deref for AdditionalSection<'a> { - type Target = RecordSection<'a>; +impl<'a, D: CompactRecordData<'a>> Deref for AdditionalSection<'a, D> { + type Target = RecordSection<'a, D>; fn deref(&self) -> &Self::Target { &self.inner } } -impl<'a> DerefMut for AdditionalSection<'a> { +impl<'a, D: CompactRecordData<'a>> DerefMut for AdditionalSection<'a, D> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } @@ -384,14 +396,15 @@ impl QuestionBuilder { } /// Appends a new question to the question section. - pub fn push(&mut self, question: &Q) -> Result<()> { + pub fn push(&mut self, question: &Question) + -> Result<()> { self.buf.push(|buf| question.push_buf(buf).map_err(|e| e.into()), |counts| counts.inc_qdcount(1)) } - pub fn push_question>(&mut self, name: N, qtype: u16, - qclass: u16) -> Result<()> { - self.push(&(name.as_ref(), qtype, qclass)) + pub fn push_question(&mut self, name: N, qtype: RRType, + qclass: Class) -> Result<()> { + self.push(&Question::new(name, qtype, qclass)) } /// Move on to the answer section @@ -432,16 +445,32 @@ impl AnswerBuilder { AnswerBuilder { buf: buf } } - pub fn push(&mut self, record: &R) -> Result<()> { + pub fn push(&mut self, record: &Record) -> Result<()> + where N: DomainName, D: RecordData { self.buf.push(|buf| record.push_buf(buf).map_err(|e| e.into()), |counts| counts.inc_ancount(1)) } + pub fn push_record(&mut self, name: N, rclass: Class, ttl: u32, + data: D) -> Result<()> + where N: DomainName, D: RecordData { + self.push(&Record::new(name, rclass, ttl, data)) + } + + /* + pub fn push>(&mut self, name: N, rclass: Class, + ttl: u32, dataop: Box) + -> Result<()> { + self.buf.push_record(name.as_ref(), rclass, ttl, dataop, + |counts| counts.inc_ancount(1)) + } + */ + pub fn authority(self) -> AuthorityBuilder { AuthorityBuilder::new(self.buf) } - /// Finish off the message and return the underlying vector. + /// Finish off the message and return the underlying message. pub fn finish(self) -> MessageBuf { self.buf.into() } @@ -474,10 +503,15 @@ impl AuthorityBuilder { AuthorityBuilder { buf: buf } } - pub fn push(&mut self, record: &R) -> Result<()> { - self.buf.push(|buf| record.push_buf(buf).map_err(|e| e.into()), - |counts| counts.inc_nscount(1)) + /* + pub fn push(&mut self, name: N, rclass: Class, ttl: u32, + dataop: F) -> Result<()> + where N: AsRef, + F: FnOnce(&mut Vec) -> RRType { + self.buf.push_record(name.as_ref(), rclass, ttl, dataop, + |counts| counts.inc_ancount(1)) } + */ pub fn additional(self) -> AdditionalBuilder { AdditionalBuilder::new(self.buf) @@ -516,10 +550,15 @@ impl AdditionalBuilder { AdditionalBuilder { buf: buf } } - pub fn push(&mut self, record: &R) -> Result<()> { - self.buf.push(|buf| record.push_buf(buf).map_err(|e| e.into()), - |counts| counts.inc_arcount(1)) + /* + pub fn push(&mut self, name: N, rclass: Class, ttl: u32, + dataop: F) -> Result<()> + where N: AsRef, + F: FnOnce(&mut Vec) -> RRType { + self.buf.push_record(name.as_ref(), rclass, ttl, dataop, + |counts| counts.inc_ancount(1)) } + */ /// Finish off the message and return the underlying vector. pub fn finish(self) -> MessageBuf { @@ -724,6 +763,31 @@ impl MessageVec { } } + /* + fn push_record(&mut self, name: &DomainNameSlice, rclass: Class, + ttl: u32, dataop: Box, incop: I) -> Result<()> + where + I: FnOnce(&mut HeaderCounts) -> bytes::Result<()> { + let buildop = |buf: &mut MessageVec| { + try!(name.push_buf_compressed(buf)); + let type_pos = buf.pos(); + buf.push_u16(0); + rclass.push_buf(buf); + buf.push_u32(ttl); + let len_pos = buf.pos(); + buf.push_u16(0); + let rtype = dataop(&mut buf.vec); + let delta = buf.pos(); + if delta > (::std::u16::MAX as usize) { + return Err(Error::OctetError(bytes::Error::Overflow)); + } + buf.update_u16(type_pos, rtype.to_int()); + buf.update_u16(len_pos, delta as u16); + Ok(()) + }; + self.push(buildop, incop) + } + */ } @@ -746,7 +810,7 @@ impl BytesBuf for MessageVec { self.compress.is_some() } - fn add_name_pos>(&mut self, name: N) { + fn add_name_pos>(&mut self, name: N) { if self.truncated { return } if let Some(ref mut map) = self.compress { if self.vec.len() >= 65535 { return } @@ -755,7 +819,7 @@ impl BytesBuf for MessageVec { } } - fn get_name_pos>(&self, name: N) -> Option { + fn get_name_pos>(&self, name: N) -> Option { match self.compress { Some(ref map) => map.get(name.as_ref()).map(|x| *x), None => None @@ -820,4 +884,29 @@ impl fmt::Display for Error { pub type Result = result::Result; +//============ Testing ====================================================== +#[cfg(test)] +mod test { + use std::net::Ipv4Addr; + use super::super::iana::{Class, RRType}; + use super::super::name::DomainNameBuf; + use super::super::rdata::rfc1035::{A, NS}; + use super::*; + + #[test] + fn build_message() { + let mut msg = MessageBuilder::new(1550, 0, true).question(); + msg.push_question(DomainNameBuf::from_str("example.com.").unwrap(), + RRType::A, Class::IN).unwrap(); + let mut msg = msg.answer(); + let data = A::new(Ipv4Addr::new(127, 0, 0, 1)); + msg.push_record(DomainNameBuf::from_str("example.com.").unwrap(), + Class::IN, 3600, data).unwrap(); + let data = NS::new(DomainNameBuf::from_str("ns.example.com.").unwrap()); + msg.push_record(DomainNameBuf::from_str("example.com.").unwrap(), + Class::IN, 3600, data).unwrap(); + let _ = msg.finish(); + } +} + diff --git a/src/name.rs b/src/name.rs index f1818a9e..91c6f714 100644 --- a/src/name.rs +++ b/src/name.rs @@ -18,25 +18,48 @@ use super::bytes::{self, BytesBuf, BytesSlice}; //------------ DomainName --------------------------------------------------- +/// A trait common to all domain name types. +/// +/// This trait only exists so that composed types containing domain names +/// can be generic over the various domain name types we have. The common +/// functionality, however, is very limited. +/// +pub trait DomainName: fmt::Display { + /// Converts the domain name into an owned domain name. + fn to_owned(&self) -> Result; + + /// Converts the domain name into a self-contained cow. + fn to_cow(&self) -> Result>; + + /// Pushes the domain name to the end of theprovided buffer. + fn push_buf(&self, buf: &mut B) -> Result<()>; + + /// Pushes the domain name to buffer using name compression. + fn push_buf_compressed(&self, buf: &mut B) -> Result<()>; +} + + +//------------ DomainNameSlice ---------------------------------------------- + /// A byte slice representing a self-contained domain name. /// /// This is an *unsized* type. /// #[derive(Debug)] -pub struct DomainName { +pub struct DomainNameSlice { slice: [u8] } /// # Creation and Conversion /// -impl DomainName { +impl DomainNameSlice { /// Create a domain name slice from a bytes slice. /// /// This is only safe if the slice follows the encoding rules and does /// not contain a compressed label. /// - unsafe fn from_bytes(slice: &[u8]) -> &DomainName { + unsafe fn from_bytes(slice: &[u8]) -> &DomainNameSlice { mem::transmute(slice) } @@ -79,7 +102,7 @@ impl DomainName { /// # Properties /// -impl DomainName { +impl DomainNameSlice { /// Checks whether the domain name is absolute. /// /// A domain name is absolute if it ends with an empty normal label @@ -99,7 +122,7 @@ impl DomainName { /// # Iteration over labels. /// -impl DomainName { +impl DomainNameSlice { /// Produces an iterator over the labels in the name. /// @@ -135,12 +158,12 @@ impl DomainName { /// # Manipulations /// -impl DomainName { +impl DomainNameSlice { /// Returns the first label and the rest of the name. /// /// Returns `None` if the name is empty. /// - pub fn split_first(&self) -> Option<(Label, &DomainName)> { + pub fn split_first(&self) -> Option<(Label, &DomainNameSlice)> { let mut iter = self.iter(); iter.next().map(|l| (l, iter.as_name())) } @@ -149,7 +172,7 @@ impl DomainName { /// /// Returns `None` for an empty domain name. Returns an empty domain /// name for a single label domain name. - pub fn parent(&self) -> Option<&DomainName> { + pub fn parent(&self) -> Option<&DomainNameSlice> { self.split_first().map(|(_, tail)| tail) } @@ -228,7 +251,15 @@ impl DomainName { } } -impl BuildDomainName for DomainName { +impl DomainName for DomainNameSlice { + fn to_owned(&self) -> Result { + Ok(self.to_owned()) + } + + fn to_cow(&self) -> Result> { + Ok(Cow::Borrowed(self)) + } + fn push_buf(&self, buf: &mut B) -> Result<()> { buf.add_name_pos(self); buf.push_bytes(&self.slice); @@ -261,28 +292,28 @@ impl BuildDomainName for DomainName { } -impl AsRef for DomainName { - fn as_ref(&self) -> &DomainName { self } +impl AsRef for DomainNameSlice { + fn as_ref(&self) -> &DomainNameSlice { self } } -impl ToOwned for DomainName { +impl ToOwned for DomainNameSlice { type Owned = DomainNameBuf; fn to_owned(&self) -> Self::Owned { self.to_owned() } } -impl + ?Sized> PartialEq for DomainName { +impl + ?Sized> PartialEq for DomainNameSlice { fn eq(&self, other: &T) -> bool { self.iter().eq(other.as_ref().iter()) } } -impl<'a> PartialEq> for DomainName { +impl<'a> PartialEq> for DomainNameSlice { /// Test whether `self` and `other` are equal. /// /// An unparsable `other` always compares false. - fn eq(&self, other: &WireDomainName) -> bool { + fn eq(&self, other: &CompactDomainName) -> bool { let mut self_iter = self.iter(); let mut other_iter = other.iter(); loop { @@ -297,13 +328,13 @@ impl<'a> PartialEq> for DomainName { } } -//impl + ?Sized> PartialEq for DomainName { +//impl + ?Sized> PartialEq for DomainNameSlice { // fn eq(&self, other: &T) -> bool { -impl PartialEq for DomainName { +impl PartialEq for DomainNameSlice { fn eq(&self, other: &str) -> bool { if !other.is_ascii() { return false } let mut other = other.as_bytes(); - let mut name = unsafe { DomainName::from_bytes(&self.slice) }; + let mut name = unsafe { DomainNameSlice::from_bytes(&self.slice) }; loop { let (label, tail) = match name.split_first() { Some(x) => x, @@ -321,17 +352,17 @@ impl PartialEq for DomainName { } } -impl cmp::Eq for DomainName { } +impl cmp::Eq for DomainNameSlice { } -impl + ?Sized> PartialOrd for DomainName { +impl + ?Sized> PartialOrd for DomainNameSlice { fn partial_cmp(&self, other: &T) -> Option { self.iter().partial_cmp(other.as_ref().iter()) } } -impl<'a> PartialOrd> for DomainName { - fn partial_cmp(&self, other: &WireDomainName) -> Option { +impl<'a> PartialOrd> for DomainNameSlice { + fn partial_cmp(&self, other: &CompactDomainName) -> Option { let mut self_iter = self.iter(); let mut other_iter = other.iter(); loop { @@ -351,14 +382,14 @@ impl<'a> PartialOrd> for DomainName { } } -impl Ord for DomainName { +impl Ord for DomainNameSlice { fn cmp(&self, other: &Self) -> cmp::Ordering { self.iter().cmp(other.iter()) } } -impl hash::Hash for DomainName { +impl hash::Hash for DomainNameSlice { fn hash(&self, state: &mut H) { use std::hash::Hash; @@ -368,7 +399,7 @@ impl hash::Hash for DomainName { } } -impl fmt::Display for DomainName { +impl fmt::Display for DomainNameSlice { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.to_string().fmt(f) } @@ -459,9 +490,9 @@ impl DomainNameBuf { Ok(res) } - /// Coerces to a `DomainName` slice. + /// Coerces to a `DomainNameSlice` slice. /// - pub fn as_name(&self) -> &DomainName { + pub fn as_name(&self) -> &DomainNameSlice { self } @@ -488,19 +519,38 @@ impl DomainNameBuf { /// /// XXX Is this a good rule? Checking for absolute names is costly. /// - pub fn append>(&mut self, name: N) { + pub fn append>(&mut self, name: N) { self._append(name.as_ref()) } - fn _append(&mut self, name: &DomainName) { + fn _append(&mut self, name: &DomainNameSlice) { if !self.is_absolute() { self.inner.extend(&name.slice) } } } -impl<'a> From<&'a DomainName> for DomainNameBuf { - fn from(n: &'a DomainName) -> DomainNameBuf { +impl DomainName for DomainNameBuf { + fn to_owned(&self) -> Result { + Ok(self.clone()) + } + + fn to_cow(&self) -> Result> { + Ok(Cow::Borrowed(&self)) + } + + fn push_buf(&self, buf: &mut B) -> Result<()> { + self.deref().push_buf(buf) + } + + fn push_buf_compressed(&self, buf: &mut B) -> Result<()> { + self.deref().push_buf_compressed(buf) + } +} + + +impl<'a> From<&'a DomainNameSlice> for DomainNameBuf { + fn from(n: &'a DomainNameSlice) -> DomainNameBuf { unsafe { DomainNameBuf::from_bytes(&n.slice) } } } @@ -515,22 +565,22 @@ impl str::FromStr for DomainNameBuf { } impl Deref for DomainNameBuf { - type Target = DomainName; + type Target = DomainNameSlice; fn deref(&self) -> &Self::Target { - unsafe { DomainName::from_bytes(&self.inner) } + unsafe { DomainNameSlice::from_bytes(&self.inner) } } } -impl Borrow for DomainNameBuf { - fn borrow(&self) -> &DomainName { +impl Borrow for DomainNameBuf { + fn borrow(&self) -> &DomainNameSlice { self.deref() } } -impl AsRef for DomainNameBuf { - fn as_ref(&self) -> &DomainName { self } +impl AsRef for DomainNameBuf { + fn as_ref(&self) -> &DomainNameSlice { self } } @@ -561,16 +611,22 @@ impl hash::Hash for DomainNameBuf { } -//------------ WireDomainName ---------------------------------------------- +impl fmt::Display for DomainNameBuf { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.deref().fmt(f) + } +} -/// A domain name embedded in a DNS message. +//------------ CompactDomainName -------------------------------------------- + +/// A reference to a possibly compressed domain name. /// -/// A wire domain name is not self-contained but rather may reference +/// This domain name is not self-contained but rather may reference /// another domain name. Because if this, it always needs a second bytes /// slice representing the message and called the *context*. /// #[derive(Clone, Debug)] -pub struct WireDomainName<'a> { +pub struct CompactDomainName<'a> { slice: &'a [u8], context: &'a [u8], } @@ -578,21 +634,21 @@ pub struct WireDomainName<'a> { /// # Creation and Conversion /// -impl<'a> WireDomainName<'a> { - /// Creates a new wire domain name from its components. - pub fn new(slice: &'a[u8], context: &'a[u8]) -> WireDomainName<'a> { - WireDomainName { slice: slice, context: context } +impl<'a> CompactDomainName<'a> { + /// Creates a new domain name from its components. + pub fn new(slice: &'a[u8], context: &'a[u8]) -> CompactDomainName<'a> { + CompactDomainName { slice: slice, context: context } } /// Splits a wire domain name from the beginning of a bytes slice. pub fn split_from(slice: &'a[u8], context: &'a[u8]) - -> Result<(WireDomainName<'a>, &'a[u8])> { + -> Result<(CompactDomainName<'a>, &'a[u8])> { let mut pos = 0; loop { let (end, head) = try!(Label::peek(slice, pos)); if head.is_final() { let (bytes, slice) = try!(slice.split_bytes(end)); - return Ok((WireDomainName::new(bytes, context), slice)); + return Ok((CompactDomainName::new(bytes, context), slice)); } pos = end; } @@ -608,7 +664,7 @@ impl<'a> WireDomainName<'a> { /// If `self` does not contain any compressed labels, it will be /// coerced into a regular domain name slice. If it does, it will be /// converted into an owned domain name. - pub fn decompress(&self) -> Result> { + pub fn decompress(&self) -> Result> { // Walk over the name and return it if it ends without compression. let mut pos = 0; loop { @@ -616,7 +672,7 @@ impl<'a> WireDomainName<'a> { match head { LabelHead::Normal(0) => { let name = unsafe { - DomainName::from_bytes(&self.slice[..end]) + DomainNameSlice::from_bytes(&self.slice[..end]) }; return Ok(Cow::Borrowed(name)); } @@ -630,7 +686,7 @@ impl<'a> WireDomainName<'a> { // iterate over the rest and append each label. let (bytes, slice) = try!(self.slice.split_bytes(pos)); let mut res = unsafe { DomainNameBuf::from_bytes(bytes) }; - for label in WireIter::new(slice, self.context) { + for label in CompactIter::new(slice, self.context) { let label = try!(label); res.push(label) } @@ -653,15 +709,23 @@ impl<'a> WireDomainName<'a> { // # Iteration over Labels // -impl<'a> WireDomainName<'a> { +impl<'a> CompactDomainName<'a> { /// Returns an iterator over the labels. - pub fn iter(&self) -> WireIter<'a> { - WireIter::new(self.slice, self.context) + pub fn iter(&self) -> CompactIter<'a> { + CompactIter::new(self.slice, self.context) } } -impl<'a> BuildDomainName for WireDomainName<'a> { +impl<'a> DomainName for CompactDomainName<'a> { + fn to_owned(&self) -> Result { + self.to_owned() + } + + fn to_cow(&self) -> Result> { + self.decompress() + } + fn push_buf(&self, buf: &mut O) -> Result<()> { for label in self.iter() { try!(label).push_buf(buf) @@ -675,27 +739,27 @@ impl<'a> BuildDomainName for WireDomainName<'a> { } -impl<'a> PartialEq for WireDomainName<'a> { - fn eq(&self, other: &WireDomainName) -> bool { +impl<'a> PartialEq for CompactDomainName<'a> { + fn eq(&self, other: &CompactDomainName) -> bool { self.iter().eq(other.iter()) } } -impl<'a, T: AsRef + ?Sized> PartialEq for WireDomainName<'a> +impl<'a, T: AsRef + ?Sized> PartialEq for CompactDomainName<'a> { fn eq(&self, other: &T) -> bool { other.as_ref().eq(self) } } -impl<'a, T: AsRef + ?Sized> PartialOrd for WireDomainName<'a> +impl<'a, T: AsRef + ?Sized> PartialOrd for CompactDomainName<'a> { fn partial_cmp(&self, other: &T) -> Option { other.as_ref().partial_cmp(self).map(|o| o.reverse()) } } -impl<'a> fmt::Display for WireDomainName<'a> { +impl<'a> fmt::Display for CompactDomainName<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.to_string() { Ok(s) => s.fmt(f), @@ -715,8 +779,8 @@ pub struct NameIter<'a> { impl<'a> NameIter<'a> { /// Returns the domain name for the remaining portion. - pub fn as_name(&self) -> &'a DomainName { - unsafe { DomainName::from_bytes(self.slice) } + pub fn as_name(&self) -> &'a DomainNameSlice { + unsafe { DomainNameSlice::from_bytes(self.slice) } } } @@ -734,26 +798,26 @@ impl<'a> Iterator for NameIter<'a> { } -//------------ WireIter ---------------------------------------------------- +//------------ CompactIter -------------------------------------------------- /// An iterator over the labels in a frail domain name. #[derive(Clone, Debug)] -pub struct WireIter<'a> { +pub struct CompactIter<'a> { slice: &'a[u8], context: &'a[u8], } -impl<'a> WireIter<'a> { - fn new(slice: &'a[u8], context: &'a[u8]) -> WireIter<'a> { - WireIter { slice: slice, context: context } +impl<'a> CompactIter<'a> { + fn new(slice: &'a[u8], context: &'a[u8]) -> CompactIter<'a> { + CompactIter { slice: slice, context: context } } - pub fn as_name(&self) -> Result> { - WireDomainName::new(self.slice, self.context).decompress() + pub fn as_name(&self) -> Result> { + CompactDomainName::new(self.slice, self.context).decompress() } } -impl<'a> Iterator for WireIter<'a> { +impl<'a> Iterator for CompactIter<'a> { type Item = Result>; fn next(&mut self) -> Option { @@ -1158,15 +1222,6 @@ impl LabelHead { } -//------------ BuildDomainName ---------------------------------------------- - -/// A trait for types that are able to construct a domain name. -pub trait BuildDomainName { - fn push_buf(&self, o: &mut O) -> Result<()>; - fn push_buf_compressed(&self, o: &mut O) -> Result<()>; -} - - //------------ Error and Result --------------------------------------------- #[derive(Clone, Debug, PartialEq)] diff --git a/src/question.rs b/src/question.rs index bf8d9a00..0fe6808b 100644 --- a/src/question.rs +++ b/src/question.rs @@ -1,107 +1,40 @@ //! A single question from a DNS message //! -use std::borrow::Cow; use std::convert; use std::error; use std::fmt; use std::result; use super::iana::{Class, RRType}; -use super::name::{self, BuildDomainName, DomainName, DomainNameBuf, - WireDomainName}; +use super::name::{self, DomainName, DomainNameBuf, DomainNameSlice, + CompactDomainName}; use super::bytes::{self, BytesSlice, BytesBuf}; -//------------ QuestionBuf -------------------------------------------------- +//------------ Question ----------------------------------------------------- -/// An owned question. -/// #[derive(Debug)] -pub struct QuestionBuf { - qname: DomainNameBuf, +pub struct Question { + qname: N, qtype: RRType, qclass: Class, } -/// # Creation and Conversion -/// -impl QuestionBuf { - /// Creates a new empty question. - /// - /// The domain name will be empty, the type will be 0, and the class - /// will be 1 (IN). - /// - pub fn new() -> QuestionBuf { - QuestionBuf { qname: DomainNameBuf::new(), qtype: RRType::Int(0), - qclass: Class::IN } +type QuestionSlice<'a> = Question<&'a DomainNameSlice>; +type QuestionBuf = Question; +type CompactQuestion<'a> = Question>; + + +//--- Common functions and methods + +impl Question { + pub fn new(qname: N, qtype: RRType, qclass: Class) -> Self { + Question { qname: qname, qtype: qtype, qclass: qclass } } - pub fn from_args(name: DomainNameBuf, qtype: RRType, qclass: Class) - -> QuestionBuf { - QuestionBuf { qname: name, qtype: qtype, qclass: qclass } - } -} - - -impl BuildQuestion for QuestionBuf { - fn push_buf(&self, buf: &mut B) -> Result<()> { - try!(self.qname.push_buf(buf)); - self.qtype.push_buf(buf); - self.qclass.push_buf(buf); - Ok(()) - } -} - - -//------------ WireQuestion ------------------------------------------------- - -#[derive(Debug)] -pub struct WireQuestion<'a> { - qname: WireDomainName<'a>, - qtype: RRType, - qclass: Class, -} - -/// # Creation and Conversion -/// -impl<'a> WireQuestion<'a> { - /// Creates a new frail question. - /// - pub fn new(qname: WireDomainName<'a>, qtype: RRType, qclass: Class) - -> WireQuestion<'a> { - WireQuestion { qname: qname, qtype: qtype, qclass: qclass } - } - - /// Splits a questions from the front of a byte slice. - /// - pub fn split_from(slice: &'a[u8], context: &'a[u8]) - -> Result<(WireQuestion<'a>, &'a[u8])> { - let (qname, slice) = try!(WireDomainName::split_from(slice, - context)); - let (qtype, slice) = try!(slice.split_u16()); - let (qclass, slice) = try!(slice.split_u16()); - Ok((WireQuestion::new(qname, qtype.into(), qclass.into()), slice)) - } - - /// Converts `self` to an owned `QuestionBuf`. - /// - pub fn to_owned(&self) -> Result { - Ok(QuestionBuf { qname: try!(self.qname.to_owned()), - qtype: self.qtype, qclass: self.qclass }) - } -} - -/// # Element access -/// -impl<'a> WireQuestion<'a> { /// Returns the requested domain name. - pub fn qname(&self) -> WireDomainName<'a> { - self.qname.clone() - } - - /// Returns the uncompressed requested domain name. - pub fn decompressed_qname(&self) -> Result> { - Ok(try!(self.qname.decompress())) + pub fn qname(&self) -> &N { + &self.qname } /// Returns the requested record type. @@ -113,12 +46,9 @@ impl<'a> WireQuestion<'a> { pub fn qclass(&self) -> Class { self.qclass } -} - -impl<'a> BuildQuestion for WireQuestion<'a> { - fn push_buf(&self, buf: &mut B) -> Result<()> { - try!(self.qname.push_buf(buf)); + pub fn push_buf(&self, buf: &mut B) -> Result<()> { + try!(self.qname.push_buf_compressed(buf)); self.qtype.push_buf(buf); self.qclass.push_buf(buf); Ok(()) @@ -126,20 +56,32 @@ impl<'a> BuildQuestion for WireQuestion<'a> { } -//----------- BuildQuestion ------------------------------------------------- +//--- Addtional functions and methods for owned questions -pub trait BuildQuestion { - fn push_buf(&self, buf: &mut B) -> Result<()>; -} - -impl<'a> BuildQuestion for (&'a DomainName, u16, u16) { - fn push_buf(&self, buf: &mut B) -> Result<()> { - try!(self.0.push_buf(buf)); - buf.push_u16(self.1); - buf.push_u16(self.2); - Ok(()) +impl Default for Question { + fn default() -> Self { + Question { qname: DomainNameBuf::new(), qtype: RRType::A, + qclass: Class::IN } } } + + +//--- Addtional functions and methods for compact questions + +impl<'a> Question> { + + /// Splits a questions from the front of a byte slice. + /// + pub fn split_from(slice: &'a[u8], context: &'a[u8]) + -> Result<(Self, &'a[u8])> { + let (qname, slice) = try!(CompactDomainName::split_from(slice, + context)); + let (qtype, slice) = try!(slice.split_u16()); + let (qclass, slice) = try!(slice.split_u16()); + Ok((Question::new(qname, qtype.into(), qclass.into()), slice)) + } +} + //------------ Error and Result --------------------------------------------- diff --git a/src/rdata/generic.rs b/src/rdata/generic.rs new file mode 100644 index 00000000..5bd19592 --- /dev/null +++ b/src/rdata/generic.rs @@ -0,0 +1,93 @@ +//! Generic Record Data Types + +use std::fmt; +use super::super::bytes::BytesBuf; +use super::super::iana::RRType; +use super::super::name::CompactDomainName; +use super::traits::{RecordData, CompactRecordData, Result}; + + +//------------ GenericRecordData -------------------------------------------- + +/// A slice of generic record data. +/// +pub struct GenericRecordData<'a> { + rtype: RRType, + data: &'a [u8], +} + +impl<'a> GenericRecordData<'a> { + pub fn new(rtype: RRType, data: &'a[u8]) -> Self { + GenericRecordData { rtype: rtype, data: data } + } +} + +impl<'a> RecordData for GenericRecordData<'a> { + fn rtype(&self) -> RRType { + self.rtype + } + + fn push_buf(&self, buf: &mut B) -> Result<()> { + buf.push_bytes(self.data); + Ok(()) + } +} + + +//------------ CompactGenericRecordData ------------------------------------- + +pub struct CompactGenericRecordData<'a> { + rtype: RRType, + data: &'a [u8], + context: &'a [u8], +} + +impl<'a> CompactGenericRecordData<'a> { + pub fn new(rtype: RRType, data: &'a[u8], context: &'a[u8]) -> Self { + CompactGenericRecordData { rtype: rtype, data: data, + context: context } + } + + pub fn rtype(&self) -> RRType { self.rtype } + pub fn data(&self) -> &[u8] { self.data } + pub fn context(&self) -> &[u8] { self.context } + + pub fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + where C: CompactRecordData<'a> + fmt::Display { + match C::from_bytes(self.rtype, self.data, self.context) { + Err(..) => Ok(()), + Ok(None) => Ok(()), + Ok(Some(data)) => data.fmt(f) + } + } +} + +impl<'a> RecordData for CompactGenericRecordData<'a> { + fn rtype(&self) -> RRType { + self.rtype + } + + fn push_buf(&self, buf: &mut B) -> Result<()> { + buf.push_bytes(self.data); + Ok(()) + } +} + +impl<'a> CompactRecordData<'a> for CompactGenericRecordData<'a> { + fn from_bytes(rtype: RRType, slice: &'a[u8], context: &'a[u8]) + -> Result> { + Ok(Some(CompactGenericRecordData::new(rtype, slice, context))) + } +} + +impl<'a> fmt::Display for CompactGenericRecordData<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use super::rfc1035::*; + + match self.rtype { + RRType::A => self.fmt::(f), + RRType::NS => self.fmt::>>(f), + _ => "...".fmt(f) + } + } +} diff --git a/src/rdata/mod.rs b/src/rdata/mod.rs index 2dd17fb1..fec045cc 100644 --- a/src/rdata/mod.rs +++ b/src/rdata/mod.rs @@ -1,4 +1,6 @@ //! Resource data handling. pub mod traits; +pub mod generic; + pub mod rfc1035; diff --git a/src/rdata/rfc1035.rs b/src/rdata/rfc1035.rs index e1b929ae..b9dacc4f 100644 --- a/src/rdata/rfc1035.rs +++ b/src/rdata/rfc1035.rs @@ -1,24 +1,30 @@ -use std::borrow::Cow; +use std::fmt; use std::net; -use ::bytes::{BytesBuf, BytesSlice}; -use ::question::Result; -use ::name::{BuildDomainName, DomainName, DomainNameBuf, WireDomainName}; -use super::traits::ConcreteRecordData; +use super::super::bytes::{BytesBuf, BytesSlice}; +use super::super::iana::RRType; +use super::super::name::{DomainName, CompactDomainName}; +use super::super::question::Result; +use super::traits::{ConcreteRecordData, CompactConcreteRecordData}; + + +//------------ A ------------------------------------------------------------ #[derive(Clone, Debug)] pub struct A { - pub addr: net::Ipv4Addr, + addr: net::Ipv4Addr, } impl A { pub fn new(addr: net::Ipv4Addr) -> A { A { addr: addr } } + + pub fn addr(&self) -> &net::Ipv4Addr { &self.addr } + pub fn addr_mut(&mut self) -> &mut net::Ipv4Addr { &mut self.addr } } impl<'a> ConcreteRecordData<'a> for A { - fn rtype() -> u16 { 1 } - fn rname() -> &'static str { "A" } + fn rtype() -> RRType { RRType::A } fn push_buf(&self, buf: &mut B) -> Result<()> { for i in self.addr.octets().iter() { @@ -26,7 +32,9 @@ impl<'a> ConcreteRecordData<'a> for A { } Ok(()) } +} +impl<'a> CompactConcreteRecordData<'a> for A { fn parse(rdata: &'a[u8], _: &[u8]) -> Result { let (a, rdata) = try!(rdata.split_u8()); let (b, rdata) = try!(rdata.split_u8()); @@ -34,46 +42,51 @@ impl<'a> ConcreteRecordData<'a> for A { let (d, _) = try!(rdata.split_u8()); Ok(A::new(net::Ipv4Addr::new(a, b, c, d))) } - - fn to_owned(&self) -> Self { - self.clone() +} + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.addr.fmt(f) } } -pub struct NS<'a> { - pub nsdname: Cow<'a, DomainName>, +//------------ NS ----------------------------------------------------------- + +#[derive(Debug)] +pub struct NS { + nsdname: N } -impl<'a> NS<'a> { - pub fn new(nsdname: Cow<'a, DomainName>) -> Self { +impl NS { + pub fn new(nsdname: N) -> Self { NS { nsdname: nsdname } } - pub fn nsdname(&self) -> &DomainName { + pub fn nsdname(&self) -> &N { &self.nsdname } - - pub fn nsdname_mut(&mut self) -> &mut DomainNameBuf { - self.nsdname.to_mut() - } } -impl<'a> ConcreteRecordData<'a> for NS<'a> { - fn rtype() -> u16 { 2 } - fn rname() -> &'static str { "NS" } +impl<'a, N: DomainName> ConcreteRecordData<'a> for NS { + fn rtype() -> RRType { RRType::NS } fn push_buf(&self, buf: &mut B) -> Result<()> { - try!(self.nsdname.push_buf(buf)); + try!(self.nsdname.push_buf_compressed(buf)); Ok(()) } +} +impl<'a> CompactConcreteRecordData<'a> for NS> { fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result { - let (name, _) = try!(WireDomainName::split_from(rdata, context)); - Ok(NS::new(try!(name.decompress()))) - } - - fn to_owned(&self) -> Self { - NS { nsdname: self.nsdname.to_owned() } + let (name, _) = try!(CompactDomainName::split_from(rdata, context)); + Ok(NS::new(name)) + } +} + + +impl fmt::Display for NS { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.nsdname.fmt(f) } } diff --git a/src/rdata/traits.rs b/src/rdata/traits.rs index 4777c31b..96b89966 100644 --- a/src/rdata/traits.rs +++ b/src/rdata/traits.rs @@ -1,43 +1,88 @@ -use ::bytes::{BytesBuf}; -use ::question::Result; +//! Traits for record data. +//! +//! There is two classes of traits in here. The more basic two traits, +//! `RecordData` and `CompactRecordData`, need to be implemented by all +//! types. They represent creating and parsing record data, respectively. +//! They are split since some record data types contain domain names and +//! while creation is possible with all name types, parsing is only +//! available with `CompactDomainName`. +//! +//! The second two traits are for types that implement exactly one type +//! of record data. They exist to avoid having to implement certain +//! functionality multiple times. They contain implementations for the +//! first two traits. -pub trait BuildRecordData { - fn rtype(&self) -> u16; +use super::super::bytes::{BytesBuf}; +use super::super::iana::RRType; +pub use super::super::question::Result; // XXX Temporary + + +//------------ Basic Traits ------------------------------------------------- + +/// A trait for creating record data. +pub trait RecordData { + /// Returns the record type for this record data instance. + fn rtype(&self) -> RRType; + + /// Appends the record data to the end of a buffer. fn push_buf(&self, buf: &mut B) -> Result<()>; } -pub trait RecordDataSlice<'a>: Sized { - type Owned: BuildRecordData; - - fn parse(rtype: u16, rdata: &'a[u8], context: &'a [u8]) - -> Result>; - fn to_owned(&self) -> Self::Owned; +/// A trait for parsing record data. +pub trait CompactRecordData<'a>: RecordData + Sized { + /// Parses the record data from the slice if the type is right. + /// + /// If this record data type does not feel responsible for records of + /// type `rtype`, it should return `Ok(None)`. Otherwise it should + /// return something or an error if parsing fails. + /// + /// The `context` argument contains the slice of the entire DNS + /// message for giving to `CompactDomainName`s. + fn from_bytes(rtype: RRType, slice: &'a[u8], context: &'a[u8]) + -> Result>; } + +//------------ Traits for Concrete Types ------------------------------------ + +/// A trait for creating concrete record data. +/// +/// This is the companion trait to `RecordData`. The only difference is that +/// `rtype()` is an associated function instead of a method since all records +/// with this data have the same type. pub trait ConcreteRecordData<'a>: Sized { - fn rtype() -> u16; - fn rname() -> &'static str; + /// Returns the record type for all records of this data type. + fn rtype() -> RRType; + + /// Appends the record data to the end of a buffer. fn push_buf(&self, buf: &mut B) -> Result<()>; - fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result; - fn to_owned(&self) -> Self; } -impl<'a, C: ConcreteRecordData<'a>> BuildRecordData for C { - fn rtype(&self) -> u16 { Self::rtype() } +/// A trait for parsing concrete record data. +/// +/// This is the companion trait to `CompactRecordData`. +pub trait CompactConcreteRecordData<'a>: ConcreteRecordData<'a> + Sized { + /// Parses the record data from the slice. + /// + /// Since the function is only ever called if the record type was + /// right, there is no need for an `Option`. + fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result; +} + +impl<'a, C: ConcreteRecordData<'a>> RecordData for C { + fn rtype(&self) -> RRType { + Self::rtype() + } + fn push_buf(&self, buf: &mut B) -> Result<()> { self.push_buf(buf) } } -impl<'a, C: ConcreteRecordData<'a>> RecordDataSlice<'a> for C { - type Owned = Self; - - fn parse(rtype: u16, rdata: &'a[u8], context: &'a [u8]) +impl<'a, C: CompactConcreteRecordData<'a>> CompactRecordData<'a> for C { + fn from_bytes(rtype: RRType, rdata: &'a[u8], context: &'a [u8]) -> Result> { if rtype != Self::rtype() { Ok(None) } else { Ok(Some(try!(Self::parse(rdata, context)))) } } - fn to_owned(&self) -> Self { - self.to_owned() - } } diff --git a/src/record.rs b/src/record.rs index 4694f502..fcad4e38 100644 --- a/src/record.rs +++ b/src/record.rs @@ -1,36 +1,31 @@ -use std::borrow::Cow; -use super::name::{BuildDomainName, DomainName, DomainNameBuf, WireDomainName}; +use super::name::{DomainName, CompactDomainName}; use super::bytes::{self, BytesSlice, BytesBuf}; -use super::question::{Result, Error}; // XXX Temporary. +use super::question::Result; // XXX Temporary. use super::iana::{Class, RRType}; -use super::rdata::traits::{BuildRecordData, RecordDataSlice}; +use super::rdata::traits::{RecordData, CompactRecordData}; -//------------ RecordBuf ---------------------------------------------------- + +//------------ Record ------------------------------------------------------- #[derive(Debug)] -pub struct RecordBuf { - name: DomainNameBuf, +pub struct Record { + name: N, rclass: Class, ttl: u32, - rdata: D, + rdata: D } -impl RecordBuf { - /// Creates a new empty record. - pub fn new>(name: &N, rclass: Class, ttl: u32, - rdata: D) -> Self { - RecordBuf { name: name.as_ref().to_owned(), rclass: rclass, ttl: ttl, - rdata: rdata } + +//--- Common + +impl Record { + pub fn new(name: N, rclass: Class, ttl: u32, rdata: D) -> Self { + Record { name: name, rclass: rclass, ttl: ttl, rdata: rdata } } - pub fn rdata(&self) -> &D { &self.rdata } - pub fn rdata_mut(&mut self) -> &mut D { &mut self.rdata } -} - -impl BuildRecord for RecordBuf { - fn push_buf(&self, buf: &mut B) -> Result<()> { + pub fn push_buf(&self, buf: &mut B) -> Result<()> { try!(self.name.push_buf(buf)); - buf.push_u16(self.rdata.rtype()); + self.rdata.rtype().push_buf(buf); self.rclass.push_buf(buf); buf.push_u32(self.ttl); let pos = buf.pos(); @@ -38,87 +33,17 @@ impl BuildRecord for RecordBuf { try!(self.rdata.push_buf(buf)); let delta = buf.delta(pos); if delta > (::std::u16::MAX as usize) { - return Err(Error::OctetError(bytes::Error::Overflow)); + return Err(bytes::Error::Overflow.into()) } buf.update_u16(pos, delta as u16); Ok(()) } -} - -//------------ WireRecord -------------------------------------------------- - -#[derive(Debug)] -pub struct WireRecord<'a> { - name: WireDomainName<'a>, - rtype: RRType, - rclass: Class, - ttl: u32, - rdata: &'a[u8], - message: &'a[u8], -} - -/// # Creation and Conversion -/// -impl<'a> WireRecord<'a> { - /// Create a new raw record. - /// - pub fn new(name: WireDomainName<'a>, rtype: RRType, rclass: Class, - ttl: u32, rdata: &'a[u8], message: &'a[u8]) - -> WireRecord<'a> { - WireRecord { name: name, rtype: rtype, rclass: rclass, ttl: ttl, - rdata: rdata, message: message } - } - - /// Splits a record from the front of a bytes slice. - /// - pub fn split_from(slice: &'a[u8], context: &'a[u8]) - -> Result<(WireRecord<'a>, &'a[u8])> { - let (name, slice) = try!(WireDomainName::split_from(slice, - context)); - let (rtype, slice) = try!(slice.split_u16()); - let (rclass, slice) = try!(slice.split_u16()); - let (ttl, slice) = try!(slice.split_u32()); - let (rdlen, slice) = try!(slice.split_u16()); - let (rdata, slice) = try!(slice.split_bytes(rdlen as usize)); - Ok((WireRecord::new(name, rtype.into(), rclass.into(), ttl, rdata, - context), - slice)) - } - - /// Converts `self` into an owned record. - pub fn to_owned>(&self) - -> Result>> { - let rdata = match try!(self.rdata::()) { - None => return Ok(None), - Some(rdata) => rdata - }; - Ok(Some(RecordBuf { name: try!(self.name.to_owned()), - rclass: self.rclass, ttl: self.ttl, - rdata: rdata.to_owned() })) - } - - pub fn rdata>(&self) -> Result> { - D::parse(self.rtype.to_int(), self.rdata, self.message) - .map_err(|e| e.into()) - } -} - -/// # Element Access -/// -impl<'a> WireRecord<'a> { /// Returns the domain name. - pub fn name(&self) -> WireDomainName<'a> { - self.name.clone() - } - - /// Returns the uncompressed domain name. - pub fn decompressed_name(&self) -> Result> { - Ok(try!(self.name.decompress())) - } + pub fn name(&self) -> &N { &self.name } /// Returns the record type. - pub fn rtype(&self) -> RRType { self.rtype } + pub fn rtype(&self) -> RRType { self.rdata.rtype() } /// Returns the record class. pub fn rclass(&self) -> Class { self.rclass } @@ -127,24 +52,33 @@ impl<'a> WireRecord<'a> { pub fn ttl(&self) -> u32 { self.ttl } /// Returns the raw record data. - pub fn rdata_bytes(&self) -> &'a[u8] { self.rdata } + pub fn rdata(&self) -> &D { &self.rdata } } -impl<'a> BuildRecord for WireRecord<'a> { - fn push_buf(&self, buf: &mut B) -> Result<()> { - try!(self.name.push_buf(buf)); - self.rtype.push_buf(buf); - self.rclass.push_buf(buf); - buf.push_u32(self.ttl); - buf.push_u16(self.rdata.len() as u16); - buf.push_bytes(self.rdata); - Ok(()) + +//---- Compact record + +impl <'a, D: CompactRecordData<'a>> Record, D> { + /// Splits a record from the front of a bytes slice. + /// + pub fn split_from(slice: &'a[u8], context: &'a[u8]) + -> Result<(Option, &'a[u8])> { + let (name, slice) = try!(CompactDomainName::split_from(slice, + context)); + let (rtype, slice) = try!(slice.split_u16()); + let (rclass, slice) = try!(slice.split_u16()); + let (ttl, slice) = try!(slice.split_u32()); + let (rdlen, slice) = try!(slice.split_u16()); + let (rdata, slice) = try!(slice.split_bytes(rdlen as usize)); + match try!(D::from_bytes(rtype.into(), rdata, context)) { + None => Ok((None, slice)), + Some(rdata) => { + Ok((Some(Record::new(name, rclass.into(), ttl, rdata)), + slice)) + } + } } } -//------------ BuildRecord -------------------------------------------------- -pub trait BuildRecord { - fn push_buf(&self, buf: &mut B) -> Result<()>; -}