From 0d57d5fd9f8af05d470c8d9c0342f86e6cae8021 Mon Sep 17 00:00:00 2001 From: Vitaly _Vi Shukela Date: Thu, 6 Dec 2018 21:38:01 +0300 Subject: [PATCH] Make it suitable for editing and writing packets Not tested, allocation-intensive. Resolves #40. --- src/enums.rs | 13 ++++---- src/header.rs | 9 ++++- src/lib.rs | 5 +-- src/name.rs | 14 ++++++++ src/parser.rs | 76 ++++++++++++++++++++++++++++++++++++++++++ src/rdata/a.rs | 12 +++++-- src/rdata/aaaa.rs | 12 +++++-- src/rdata/all.rs | 5 +-- src/rdata/axfr.rs | 4 ++- src/rdata/cname.rs | 24 ++++++++++++-- src/rdata/hinfo.rs | 4 ++- src/rdata/maila.rs | 4 ++- src/rdata/mailb.rs | 4 ++- src/rdata/mb.rs | 4 ++- src/rdata/mf.rs | 4 ++- src/rdata/mg.rs | 4 ++- src/rdata/minfo.rs | 4 ++- src/rdata/mod.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++- src/rdata/mr.rs | 4 ++- src/rdata/mx.rs | 31 ++++++++++++++++- src/rdata/ns.rs | 24 ++++++++++++-- src/rdata/nsec.rs | 5 +-- src/rdata/null.rs | 4 ++- src/rdata/opt.rs | 34 ++++++++++++++++++- src/rdata/ptr.rs | 23 ++++++++++++- src/rdata/soa.rs | 44 +++++++++++++++++++++++- src/rdata/srv.rs | 37 ++++++++++++++++++++- src/rdata/txt.rs | 21 +++++++++++- src/rdata/wks.rs | 4 ++- src/structs.rs | 76 ++++++++++++++++++++++++++++++++++++++++++ 30 files changed, 552 insertions(+), 40 deletions(-) diff --git a/src/enums.rs b/src/enums.rs index 9f58ddf..7f82822 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -1,11 +1,10 @@ use {Error}; -use rdata::Record; use rdata::*; /// The TYPE value according to RFC 1035 /// /// All "EXPERIMENTAL" markers here are from the RFC -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] pub enum Type { /// a host addresss A = a::Record::TYPE, @@ -50,7 +49,7 @@ pub enum Type { /// The QTYPE value according to RFC 1035 /// /// All "EXPERIMENTAL" markers here are from the RFC -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)] #[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))] pub enum QueryType { /// a host addresss @@ -99,7 +98,7 @@ pub enum QueryType { /// The CLASS value according to RFC 1035 -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] pub enum Class { /// the Internet IN = 1, @@ -113,7 +112,7 @@ pub enum Class { } /// The QCLASS value according to RFC 1035 -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] pub enum QueryClass { /// the Internet IN = 1, @@ -129,7 +128,7 @@ pub enum QueryClass { } /// The OPCODE value according to RFC 1035 -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] pub enum Opcode { /// Normal query StandardQuery, @@ -143,7 +142,7 @@ pub enum Opcode { quick_error! { /// The RCODE value according to RFC 1035 - #[derive(Debug, PartialEq, Eq, Clone, Copy)] + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] #[allow(missing_docs)] // names are from spec pub enum ResponseCode { NoError diff --git a/src/header.rs b/src/header.rs index 01d18ad..6c95215 100644 --- a/src/header.rs +++ b/src/header.rs @@ -16,7 +16,7 @@ mod flag { } /// Represents parsed header of the packet -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] #[allow(missing_docs)] // fields are from the spec I think pub struct Header { pub id: u16, @@ -64,6 +64,13 @@ impl Header { }; Ok(header) } + + /// Similar to `write`, doing the same + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + let mut buf = [0; 12]; + self.write(&mut buf); + w.write_all(&buf) + } /// Write a header to a buffer slice /// /// # Panics diff --git a/src/lib.rs b/src/lib.rs index e89c005..52bdcd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,8 +32,9 @@ pub mod rdata; pub use enums::{Type, QueryType, Class, QueryClass, ResponseCode, Opcode}; pub use structs::{Question, ResourceRecord, Packet}; -pub use name::{Name}; +pub use structs::{QuestionBuf, ResourceRecordBuf, PacketBuf}; +pub use name::{Name, write_name_to}; pub use error::{Error}; pub use header::{Header}; -pub use rdata::{RData}; +pub use rdata::{RData,RDataBuf}; pub use builder::{Builder}; diff --git a/src/name.rs b/src/name.rs index 8763259..2f978b4 100644 --- a/src/name.rs +++ b/src/name.rs @@ -22,6 +22,20 @@ pub struct Name<'a>{ original: &'a [u8], } +/// Turn name (represented as string) back into a part of a DNS packet +/// no compression is implemented, the packet may be larger than original +/// Each part between dots must be less than 128 bytes, lest panic. +pub fn write_name_to(n: &str, mut w: W) -> ::std::io::Result<()> { + use byteorder::WriteBytesExt; + for l in n.split('.') { + assert!(l.len() < 128); + w.write_u8(l.len() as u8)?; + w.write_all(l.as_bytes())?; + } + w.write_u8(0)?; + Ok(()) +} + impl<'a> Name<'a> { /// Scan the data to get Name object /// diff --git a/src/parser.rs b/src/parser.rs index 0718798..5a45554 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,11 +3,44 @@ use std::i32; use byteorder::{BigEndian, ByteOrder}; use {Header, Packet, Error, Question, Name, QueryType, QueryClass}; +use {PacketBuf, QuestionBuf, ResourceRecordBuf, write_name_to}; use {Type, Class, ResourceRecord, RData}; use rdata::opt::Record as Opt; const OPT_RR_START: [u8; 3] = [0, 0, 41]; +impl PacketBuf { + /// Get DNS packet as bytes, writing it to specified writer + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + let mut header = self.header.clone(); + assert!(self.questions.len() < 65536); + assert!(self.answers.len() < 65536); + assert!(self.nameservers.len() < 65536); + assert!(self.additional.len() < 65536); + + header.questions = self.questions.len() as u16; + header.answers = self.answers.len() as u16; + header.nameservers = self.nameservers.len() as u16; + header.additional = self.additional.len() as u16; + + header.write_to(&mut w)?; + + for q in &self.questions { + q.write_to(&mut w)?; + } + for a in &self.answers { + a.write_to(&mut w)?; + } + for ns in &self.nameservers { + ns.write_to(&mut w)?; + } + for ad in &self.additional { + ad.write_to(&mut w)?; + } + Ok(()) + } +} + impl<'a> Packet<'a> { /// Parse a full DNS Packet and return a structure that has all the /// data borrowed from the passed buffer. @@ -68,6 +101,23 @@ impl<'a> Packet<'a> { } } +impl QuestionBuf { + /// Get DNS packet as bytes, writing it to specified writer + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + use byteorder::WriteBytesExt; + + let qtype = self.qtype as u16; + let mut qclass = self.qclass as u16; + if self.prefer_unicast { qclass |= 0x8000; } + + write_name_to(&self.qname, &mut w)?; + w.write_u16::(qtype)?; + w.write_u16::(qclass)?; + + Ok(()) + } +} + fn parse_qclass_code(value: u16) -> Result<(bool, QueryClass), Error> { let prefer_unicast = value & 0x8000 == 0x8000; let qclass_code = value & 0x7FFF; @@ -84,6 +134,32 @@ fn parse_class_code(value: u16) -> Result<(bool, Class), Error> { Ok((is_unique, cls)) } +impl ResourceRecordBuf { + /// Get DNS packet as bytes, writing it to specified writer + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + use byteorder::WriteBytesExt; + + let typ = self.data.type_code() as u16; + let mut clscode = self.cls as u16; + if self.multicast_unique { clscode |= 0x8000; } + let ttl = self.ttl; + + write_name_to(&self.name, &mut w)?; + w.write_u16::(typ)?; + w.write_u16::(clscode)?; + w.write_u32::(ttl)?; + + let mut v = Vec::with_capacity(16); + self.data.write_to(&mut v)?; + + assert!(v.len() < 65536); + w.write_u16::(v.len() as u16)?; + w.write_all(&v)?; + + Ok(()) + } +} + // Generic function to parse answer, nameservers, and additional records. fn parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result, Error> { let name = try!(Name::scan(&data[*offset..], data)); diff --git a/src/rdata/a.rs b/src/rdata/a.rs index f4196d5..bec69b3 100644 --- a/src/rdata/a.rs +++ b/src/rdata/a.rs @@ -3,13 +3,21 @@ use std::net::Ipv4Addr; use Error; use byteorder::{BigEndian, ByteOrder}; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)] pub struct Record(pub Ipv4Addr); -impl<'a> super::Record<'a> for Record { +impl Record { + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + w.write_all(&self.0.octets())?; + Ok(()) + } +} +impl super::RecordType for Record { const TYPE: isize = 1; +} +impl<'a> super::Record<'a> for Record { fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { if rdata.len() != 4 { return Err(Error::WrongRdataLength); diff --git a/src/rdata/aaaa.rs b/src/rdata/aaaa.rs index e59937a..f414b7a 100644 --- a/src/rdata/aaaa.rs +++ b/src/rdata/aaaa.rs @@ -3,13 +3,21 @@ use std::net::Ipv6Addr; use Error; use byteorder::{BigEndian, ByteOrder}; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Ord, PartialOrd, Hash)] pub struct Record(pub Ipv6Addr); -impl<'a> super::Record<'a> for Record { +impl Record { + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + w.write_all(&self.0.octets())?; + Ok(()) + } +} +impl super::RecordType for Record { const TYPE: isize = 28; +} +impl<'a> super::Record<'a> for Record { fn parse(rdata: &'a [u8], _record: &'a [u8]) -> super::RDataResult<'a> { if rdata.len() != 16 { return Err(Error::WrongRdataLength); diff --git a/src/rdata/all.rs b/src/rdata/all.rs index 106c91b..9b6e109 100644 --- a/src/rdata/all.rs +++ b/src/rdata/all.rs @@ -1,10 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; -impl<'a> super::Record<'a> for Record { - +impl super::RecordType for Record { const TYPE: isize = 255; +} +impl<'a> super::Record<'a> for Record { fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); } diff --git a/src/rdata/axfr.rs b/src/rdata/axfr.rs index b48dc1a..a9b50d0 100644 --- a/src/rdata/axfr.rs +++ b/src/rdata/axfr.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 252; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 252; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/cname.rs b/src/rdata/cname.rs index 0dcb469..285eb80 100644 --- a/src/rdata/cname.rs +++ b/src/rdata/cname.rs @@ -3,16 +3,36 @@ use Name; #[derive(Debug, Clone, Copy)] pub struct Record<'a>(pub Name<'a>); +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf(String); + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf(self.to_string()) + } +} + +impl RecordBuf { + pub fn write_to(&self,w: W) -> ::std::io::Result<()> { + super::super::write_name_to(&self.0, w)?; + Ok(()) + } +} + impl<'a> ToString for Record<'a> { #[inline] fn to_string(&self) -> String { self.0.to_string() } } - +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 5; +} +impl super::RecordType for RecordBuf { + const TYPE: isize = 5; +} impl<'a> super::Record<'a> for Record<'a> { - const TYPE: isize = 5; fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> { let name = Name::scan(rdata, original)?; diff --git a/src/rdata/hinfo.rs b/src/rdata/hinfo.rs index 6ee160b..6e0dcfa 100644 --- a/src/rdata/hinfo.rs +++ b/src/rdata/hinfo.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 13; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 13; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/maila.rs b/src/rdata/maila.rs index ab1166c..446ba64 100644 --- a/src/rdata/maila.rs +++ b/src/rdata/maila.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 254; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 254; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/mailb.rs b/src/rdata/mailb.rs index 9f043c6..487538a 100644 --- a/src/rdata/mailb.rs +++ b/src/rdata/mailb.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 253; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 253; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/mb.rs b/src/rdata/mb.rs index d14e7b4..555237d 100644 --- a/src/rdata/mb.rs +++ b/src/rdata/mb.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 7; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 7; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/mf.rs b/src/rdata/mf.rs index 11c935d..af39aaa 100644 --- a/src/rdata/mf.rs +++ b/src/rdata/mf.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 4; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 4; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/mg.rs b/src/rdata/mg.rs index 4fce456..966d350 100644 --- a/src/rdata/mg.rs +++ b/src/rdata/mg.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 8; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 8; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/minfo.rs b/src/rdata/minfo.rs index 29b3a45..2b48e51 100644 --- a/src/rdata/minfo.rs +++ b/src/rdata/minfo.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 14; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 14; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/mod.rs b/src/rdata/mod.rs index 770f46b..8f53c2d 100644 --- a/src/rdata/mod.rs +++ b/src/rdata/mod.rs @@ -40,6 +40,15 @@ pub use self::soa::Record as Soa; pub use self::srv::Record as Srv; pub use self::txt::Record as Txt; +pub use self::cname::RecordBuf as CnameBuf; +pub use self::mx::RecordBuf as MxBuf; +pub use self::ns::RecordBuf as NsBuf; +pub use self::opt::RecordBuf as OptBuf; +pub use self::ptr::RecordBuf as PtrBuf; +pub use self::soa::RecordBuf as SoaBuf; +pub use self::srv::RecordBuf as SrvBuf; +pub use self::txt::RecordBuf as TxtBuf; + pub type RDataResult<'a> = Result, Error>; /// The enumeration that represents known types of DNS resource records data @@ -58,9 +67,81 @@ pub enum RData<'a> { Unknown(Type, &'a [u8]), } -pub (crate) trait Record<'a> { +/// Owned analogue of `RData` +#[derive(Debug,Clone,Ord,Eq,Hash,PartialOrd,PartialEq)] +pub enum RDataBuf { + A(A), + AAAA(Aaaa), + CNAME(CnameBuf), + MX(MxBuf), + NS(NsBuf), + PTR(PtrBuf), + SOA(SoaBuf), + SRV(SrvBuf), + TXT(TxtBuf), + /// Anything that can't be parsed yet + Unknown(Type, Vec), +} + + +impl<'a> RData<'a> { + pub fn deep_clone(&self) -> RDataBuf { + match self { + RData::A(x) => RDataBuf::A(*x), + RData::AAAA(x) => RDataBuf::AAAA(*x), + RData::CNAME(x) => RDataBuf::CNAME(x.deep_clone()), + RData::MX(x) => RDataBuf::MX(x.deep_clone()), + RData::NS(x) => RDataBuf::NS(x.deep_clone()), + RData::PTR(x) => RDataBuf::PTR(x.deep_clone()), + RData::SOA(x) => RDataBuf::SOA(x.deep_clone()), + RData::SRV(x) => RDataBuf::SRV(x.deep_clone()), + RData::TXT(x) => RDataBuf::TXT(x.deep_clone()), + RData::Unknown(t, b) => RDataBuf::Unknown(*t, b.to_vec()), + } + } +} + +impl RDataBuf { + /// Serialize it as a part of DNS packet + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + match self { + RDataBuf::A(x) => x.write_to(w), + RDataBuf::AAAA(x) => x.write_to(w), + RDataBuf::CNAME(x) => x.write_to(w), + RDataBuf::MX(x) => x.write_to(w), + RDataBuf::NS(x) => x.write_to(w), + RDataBuf::PTR(x) => x.write_to(w), + RDataBuf::SOA(x) => x.write_to(w), + RDataBuf::SRV(x) => x.write_to(w), + RDataBuf::TXT(x) => x.write_to(w), + RDataBuf::Unknown(_t, b) => w.write_all(&b), + } + } + + /// Returns packet type as enum + /// + /// Code can be converted to an integer `packet.type_code() as isize` + pub fn type_code(&self) -> Type { + match *self { + RDataBuf::A(..) => Type::A, + RDataBuf::AAAA(..) => Type::AAAA, + RDataBuf::CNAME(..) => Type::CNAME, + RDataBuf::NS(..) => Type::NS, + RDataBuf::MX(..) => Type::MX, + RDataBuf::PTR(..) => Type::PTR, + RDataBuf::SOA(..) => Type::SOA, + RDataBuf::SRV(..) => Type::SRV, + RDataBuf::TXT(..) => Type::TXT, + RDataBuf::Unknown(t, _) => t, + } + } +} + +pub (crate) trait RecordType { const TYPE: isize; +} +pub (crate) trait Record<'a> : RecordType { fn parse(rdata: &'a [u8], original: &'a [u8]) -> RDataResult<'a>; } diff --git a/src/rdata/mr.rs b/src/rdata/mr.rs index e313372..43a7f70 100644 --- a/src/rdata/mr.rs +++ b/src/rdata/mr.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 9; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 9; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/mx.rs b/src/rdata/mx.rs index 33c5c41..dbd4970 100644 --- a/src/rdata/mx.rs +++ b/src/rdata/mx.rs @@ -7,9 +7,38 @@ pub struct Record<'a> { pub exchange: Name<'a>, } -impl<'a> super::Record<'a> for Record<'a> { +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf { + pub preference: u16, + pub exchange: String, +} + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf{ + exchange: self.exchange.to_string(), + preference: self.preference, + } + } +} +impl RecordBuf { + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + use byteorder::WriteBytesExt; + w.write_u16::(self.preference)?; + super::super::write_name_to(&self.exchange, w)?; + Ok(()) + } +} + +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 15; +} +impl super::RecordType for RecordBuf { const TYPE: isize = 15; +} +impl<'a> super::Record<'a> for Record<'a> { + fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> { if rdata.len() < 3 { diff --git a/src/rdata/ns.rs b/src/rdata/ns.rs index 42a2f29..9a90696 100644 --- a/src/rdata/ns.rs +++ b/src/rdata/ns.rs @@ -3,6 +3,22 @@ use Name; #[derive(Debug, Clone, Copy)] pub struct Record<'a>(pub Name<'a>); +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf(String); + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf(self.to_string()) + } +} + +impl RecordBuf { + pub fn write_to(&self,w: W) -> ::std::io::Result<()> { + super::super::write_name_to(&self.0, w)?; + Ok(()) + } +} + impl<'a> ToString for Record<'a> { #[inline] fn to_string(&self) -> String { @@ -10,9 +26,13 @@ impl<'a> ToString for Record<'a> { } } -impl<'a> super::Record<'a> for Record<'a> { - +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 2; +} +impl super::RecordType for RecordBuf { const TYPE: isize = 2; +} +impl<'a> super::Record<'a> for Record<'a> { fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> { let name = Name::scan(rdata, original)?; diff --git a/src/rdata/nsec.rs b/src/rdata/nsec.rs index 354c512..1802827 100644 --- a/src/rdata/nsec.rs +++ b/src/rdata/nsec.rs @@ -1,9 +1,10 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; -impl<'a> super::Record<'a> for Record { - +impl super::RecordType for Record { const TYPE: isize = 47; +} +impl<'a> super::Record<'a> for Record { fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/null.rs b/src/rdata/null.rs index b3bfcd3..40d0536 100644 --- a/src/rdata/null.rs +++ b/src/rdata/null.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 10; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 10; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/opt.rs b/src/rdata/opt.rs index 694d393..3261087 100644 --- a/src/rdata/opt.rs +++ b/src/rdata/opt.rs @@ -8,9 +8,41 @@ pub struct Record<'a> { pub data: super::RData<'a>, } -impl<'a> super::Record<'a> for Record<'a> { +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf { + pub udp: u16, + pub extrcode: u8, + pub version: u8, + pub flags: u16, + pub data: super::RDataBuf, +} + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf{ + udp: self.udp, + extrcode: self.extrcode, + version: self.version, + flags: self.flags, + data: self.data.deep_clone(), + } + } +} +impl RecordBuf { + pub fn write_to(&self,_w: W) -> ::std::io::Result<()> { + unimplemented!() + } +} + +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 41; +} +impl super::RecordType for RecordBuf { const TYPE: isize = 41; +} +impl<'a> super::Record<'a> for Record<'a> { + fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/rdata/ptr.rs b/src/rdata/ptr.rs index 315c379..a23ffd7 100644 --- a/src/rdata/ptr.rs +++ b/src/rdata/ptr.rs @@ -3,6 +3,22 @@ use Name; #[derive(Debug, Clone, Copy)] pub struct Record<'a>(pub Name<'a>); +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf(String); + +impl RecordBuf { + pub fn write_to(&self,w: W) -> ::std::io::Result<()> { + super::super::write_name_to(&self.0, w)?; + Ok(()) + } +} + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf(self.to_string()) + } +} + impl<'a> ToString for Record<'a> { #[inline] fn to_string(&self) -> String { @@ -10,9 +26,14 @@ impl<'a> ToString for Record<'a> { } } +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 12; +} +impl super::RecordType for RecordBuf { + const TYPE: isize = 12; +} impl<'a> super::Record<'a> for Record<'a> { - const TYPE: isize = 12; fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> { let name = Name::scan(rdata, original)?; diff --git a/src/rdata/soa.rs b/src/rdata/soa.rs index e6d5f17..b694c05 100644 --- a/src/rdata/soa.rs +++ b/src/rdata/soa.rs @@ -12,10 +12,52 @@ pub struct Record<'a> { pub expire: u32, pub minimum_ttl: u32, } +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf { + pub primary_ns: String, + pub mailbox: String, + pub serial: u32, + pub refresh: u32, + pub retry: u32, + pub expire: u32, + pub minimum_ttl: u32, +} -impl<'a> super::Record<'a> for Record<'a> { +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf{ + primary_ns: self.primary_ns.to_string(), + mailbox: self.mailbox.to_string(), + serial: self.serial, + refresh: self.refresh, + retry: self.retry, + expire: self.expire, + minimum_ttl: self.minimum_ttl, + } + } +} + +impl RecordBuf { + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + use byteorder::WriteBytesExt; + super::super::write_name_to(&self.primary_ns, &mut w)?; + super::super::write_name_to(&self.mailbox, &mut w)?; + w.write_u32::(self.serial)?; + w.write_u32::(self.refresh)?; + w.write_u32::(self.retry)?; + w.write_u32::(self.expire)?; + w.write_u32::(self.minimum_ttl)?; + Ok(()) + } +} +impl<'a> super::RecordType for Record<'a> { const TYPE: isize = 6; +} +impl super::RecordType for RecordBuf { + const TYPE: isize = 6; +} +impl<'a> super::Record<'a> for Record<'a> { fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> { let mut pos = 0; diff --git a/src/rdata/srv.rs b/src/rdata/srv.rs index dbc151d..a39ed0a 100644 --- a/src/rdata/srv.rs +++ b/src/rdata/srv.rs @@ -9,9 +9,44 @@ pub struct Record<'a> { pub target: Name<'a>, } -impl<'a> super::Record<'a> for Record<'a> { +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf { + pub priority: u16, + pub weight: u16, + pub port: u16, + pub target: String, +} + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf{ + priority: self.priority, + weight: self.weight, + port: self.port, + target: self.target.to_string(), + } + } +} +impl RecordBuf { + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + use byteorder::WriteBytesExt; + w.write_u16::(self.priority)?; + w.write_u16::(self.weight)?; + w.write_u16::(self.port)?; + super::super::write_name_to(&self.target, &mut w)?; + Ok(()) + } +} + +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 33; +} +impl super::RecordType for RecordBuf { const TYPE: isize = 33; +} +impl<'a> super::Record<'a> for Record<'a> { + fn parse(rdata: &'a [u8], original: &'a [u8]) -> super::RDataResult<'a> { if rdata.len() < 7 { diff --git a/src/rdata/txt.rs b/src/rdata/txt.rs index 8f5f5fc..072c505 100644 --- a/src/rdata/txt.rs +++ b/src/rdata/txt.rs @@ -4,6 +4,20 @@ use Error; pub struct Record<'a> { bytes: &'a [u8], } +#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] +pub struct RecordBuf(Vec); + +impl<'a> Record<'a> { + pub fn deep_clone(&self) -> RecordBuf { + RecordBuf(self.bytes.to_vec()) + } +} +impl RecordBuf { + pub fn write_to(&self,mut w: W) -> ::std::io::Result<()> { + w.write_all(&self.0)?; + Ok(()) + } +} #[derive(Debug)] pub struct RecordIter<'a> { @@ -34,9 +48,14 @@ impl<'a> Record<'a> { } } +impl<'a> super::RecordType for Record<'a> { + const TYPE: isize = 16; +} +impl super::RecordType for RecordBuf { + const TYPE: isize = 16; +} impl<'a> super::Record<'a> for Record<'a> { - const TYPE: isize = 16; fn parse(rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { // Just a quick check that record is valid diff --git a/src/rdata/wks.rs b/src/rdata/wks.rs index ff6e5f1..eaffadf 100644 --- a/src/rdata/wks.rs +++ b/src/rdata/wks.rs @@ -1,9 +1,11 @@ #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Record; +impl super::RecordType for Record { + const TYPE: isize = 11; +} impl<'a> super::Record<'a> for Record { - const TYPE: isize = 11; fn parse(_rdata: &'a [u8], _original: &'a [u8]) -> super::RDataResult<'a> { unimplemented!(); diff --git a/src/structs.rs b/src/structs.rs index 4f60639..54f4bb2 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,4 +1,5 @@ use {QueryType, QueryClass, Name, Class, Header, RData}; +use {RDataBuf}; use rdata::opt; @@ -19,6 +20,33 @@ pub struct Packet<'a> { pub opt: Option>, } +/// Owned analogue of `Packet` +#[derive(Debug,Hash,Ord,PartialOrd,Eq,PartialEq,Clone)] +#[allow(missing_docs)] +pub struct PacketBuf { + pub header: Header, + pub questions: Vec, + pub answers: Vec, + pub nameservers: Vec, + pub additional: Vec, + pub opt: Option, +} + +impl<'a> Packet<'a> { + /// Make fully owned, editable copy + pub fn deep_clone(&self) -> PacketBuf { + PacketBuf{ + header: self.header, + questions: self.questions.iter().map(|x|x.deep_clone()).collect(), + answers: self.answers.iter().map(|x|x.deep_clone()).collect(), + nameservers: self.nameservers.iter().map(|x|x.deep_clone()).collect(), + additional: self.additional.iter().map(|x|x.deep_clone()).collect(), + opt: self.opt.as_ref().map(|x|x.deep_clone()), + } + } +} + + /// A parsed chunk of data in the Query section of the packet #[derive(Debug)] #[allow(missing_docs)] // should be covered by spec @@ -31,6 +59,29 @@ pub struct Question<'a> { pub qclass: QueryClass, } +/// Owned analogue of `Question` +#[derive(Debug,Hash,Ord,PartialOrd,Eq,PartialEq,Clone)] +#[allow(missing_docs)] +pub struct QuestionBuf { + pub qname: String, + pub prefer_unicast: bool, + pub qtype: QueryType, + pub qclass: QueryClass, +} + +impl<'a> Question<'a> { + /// Make fully owned, editable copy + pub fn deep_clone(&self) -> QuestionBuf { + QuestionBuf{ + qname: self.qname.to_string(), + prefer_unicast: self.prefer_unicast, + qtype: self.qtype, + qclass: self.qclass, + } + } +} + + /// A single DNS record /// /// We aim to provide whole range of DNS records available. But as time is @@ -48,3 +99,28 @@ pub struct ResourceRecord<'a> { pub ttl: u32, pub data: RData<'a>, } + +/// Owned analogue of `ResourceRecord` +#[derive(Debug,Hash,Ord,PartialOrd,Eq,PartialEq,Clone)] +#[allow(missing_docs)] +pub struct ResourceRecordBuf { + pub name: String, + pub multicast_unique: bool, + pub cls: Class, + pub ttl: u32, + pub data: RDataBuf, +} + + +impl<'a> ResourceRecord<'a> { + /// Make fully owned, editable copy + pub fn deep_clone(&self) -> ResourceRecordBuf { + ResourceRecordBuf{ + name: self.name.to_string(), + multicast_unique: self.multicast_unique, + cls: self.cls, + ttl: self.ttl, + data: self.data.deep_clone(), + } + } +}