Rework record creation; add generic record data.

This commit is contained in:
Martin Hoffmann
2016-03-15 16:21:24 +01:00
parent 0b5141371f
commit 50c85ce629
12 changed files with 620 additions and 402 deletions
+3 -3
View File
@@ -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<N: AsRef<DomainName>>(&mut self, name: N) {
fn add_name_pos<N: AsRef<DomainNameSlice>>(&mut self, name: N) {
let _ = name;
}
/// Retrieves the position for `name`, if available.
fn get_name_pos<N: AsRef<DomainName>>(&self, name: N) -> Option<u16> {
fn get_name_pos<N: AsRef<DomainNameSlice>>(&self, name: N) -> Option<u16> {
let _ = name; None
}
}
+9 -7
View File
@@ -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<u16> {
Ok((if self.name.is_empty() { 2 } else { 1 }))
fn qtype(&self) -> Result<RRType> {
Ok((if self.name.is_empty() { RRType::NS } else { RRType::A }))
}
fn qclass(&self) -> Result<u16> {
Ok((1))
fn qclass(&self) -> Result<Class> {
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())
}
}
+21
View File
@@ -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<u16> for Class {
fn eq(&self, other: &u16) -> bool {
self.to_int() == *other
}
}
impl PartialEq<Class> for u16 {
fn eq(&self, other: &Class) -> bool {
*self == other.to_int()
}
}
impl Eq for Class { }
+22
View File
@@ -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<u16> for RRType {
fn eq(&self, other: &u16) -> bool {
self.to_int() == *other
}
}
impl PartialEq<RRType> for u16 {
fn eq(&self, other: &RRType) -> bool {
*self == other.to_int()
}
}
impl Eq for RRType { }
+142 -53
View File
@@ -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<AnswerSection<'a>> {
pub fn answer<D: CompactRecordData<'a>>(self)
-> Option<AnswerSection<'a, D>> {
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<WireQuestion<'a>>;
type Item = Result<Question<CompactDomainName<'a>>>;
fn next(&mut self) -> Option<Self::Item> {
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<D>,
}
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<WireRecord<'a>>;
impl<'a, D: CompactRecordData<'a>> Iterator for RecordSection<'a, D> {
type Item = Result<Record<CompactDomainName<'a>, D>>;
fn next(&mut self) -> Option<Self::Item> {
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<AuthoritySection<'a>> {
pub fn authority(self) -> Option<AuthoritySection<'a, D>> {
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<AdditionalSection<'a>> {
pub fn additional(self) -> Option<AdditionalSection<'a, D>> {
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<Q: BuildQuestion>(&mut self, question: &Q) -> Result<()> {
pub fn push<N: DomainName>(&mut self, question: &Question<N>)
-> Result<()> {
self.buf.push(|buf| question.push_buf(buf).map_err(|e| e.into()),
|counts| counts.inc_qdcount(1))
}
pub fn push_question<N: AsRef<DomainName>>(&mut self, name: N, qtype: u16,
qclass: u16) -> Result<()> {
self.push(&(name.as_ref(), qtype, qclass))
pub fn push_question<N: DomainName>(&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<R: BuildRecord>(&mut self, record: &R) -> Result<()> {
pub fn push<N, D>(&mut self, record: &Record<N, D>) -> 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<N, D>(&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<N: AsRef<DomainNameSlice>>(&mut self, name: N, rclass: Class,
ttl: u32, dataop: Box<PushDataOp>)
-> 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<R: BuildRecord>(&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<N, F>(&mut self, name: N, rclass: Class, ttl: u32,
dataop: F) -> Result<()>
where N: AsRef<DomainName>,
F: FnOnce(&mut Vec<u8>) -> 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<R: BuildRecord>(&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<N, F>(&mut self, name: N, rclass: Class, ttl: u32,
dataop: F) -> Result<()>
where N: AsRef<DomainName>,
F: FnOnce(&mut Vec<u8>) -> 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<I>(&mut self, name: &DomainNameSlice, rclass: Class,
ttl: u32, dataop: Box<PushDataOp>, 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<N: AsRef<DomainName>>(&mut self, name: N) {
fn add_name_pos<N: AsRef<DomainNameSlice>>(&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<N: AsRef<DomainName>>(&self, name: N) -> Option<u16> {
fn get_name_pos<N: AsRef<DomainNameSlice>>(&self, name: N) -> Option<u16> {
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<T> = result::Result<T, Error>;
//============ 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();
}
}
+133 -78
View File
@@ -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<DomainNameBuf>;
/// Converts the domain name into a self-contained cow.
fn to_cow(&self) -> Result<Cow<DomainNameSlice>>;
/// Pushes the domain name to the end of theprovided buffer.
fn push_buf<B: BytesBuf>(&self, buf: &mut B) -> Result<()>;
/// Pushes the domain name to buffer using name compression.
fn push_buf_compressed<B: BytesBuf>(&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<DomainNameBuf> {
Ok(self.to_owned())
}
fn to_cow(&self) -> Result<Cow<DomainNameSlice>> {
Ok(Cow::Borrowed(self))
}
fn push_buf<B: BytesBuf>(&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<DomainName> for DomainName {
fn as_ref(&self) -> &DomainName { self }
impl AsRef<DomainNameSlice> 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<T: AsRef<DomainName> + ?Sized> PartialEq<T> for DomainName {
impl<T: AsRef<DomainNameSlice> + ?Sized> PartialEq<T> for DomainNameSlice {
fn eq(&self, other: &T) -> bool {
self.iter().eq(other.as_ref().iter())
}
}
impl<'a> PartialEq<WireDomainName<'a>> for DomainName {
impl<'a> PartialEq<CompactDomainName<'a>> 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<WireDomainName<'a>> for DomainName {
}
}
//impl<T: AsRef<str> + ?Sized> PartialEq<T> for DomainName {
//impl<T: AsRef<str> + ?Sized> PartialEq<T> for DomainNameSlice {
// fn eq(&self, other: &T) -> bool {
impl PartialEq<str> for DomainName {
impl PartialEq<str> 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<str> for DomainName {
}
}
impl cmp::Eq for DomainName { }
impl cmp::Eq for DomainNameSlice { }
impl<T: AsRef<DomainName> + ?Sized> PartialOrd<T> for DomainName {
impl<T: AsRef<DomainNameSlice> + ?Sized> PartialOrd<T> for DomainNameSlice {
fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
self.iter().partial_cmp(other.as_ref().iter())
}
}
impl<'a> PartialOrd<WireDomainName<'a>> for DomainName {
fn partial_cmp(&self, other: &WireDomainName) -> Option<cmp::Ordering> {
impl<'a> PartialOrd<CompactDomainName<'a>> for DomainNameSlice {
fn partial_cmp(&self, other: &CompactDomainName) -> Option<cmp::Ordering> {
let mut self_iter = self.iter();
let mut other_iter = other.iter();
loop {
@@ -351,14 +382,14 @@ impl<'a> PartialOrd<WireDomainName<'a>> 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<H: hash::Hasher>(&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<N: AsRef<DomainName>>(&mut self, name: N) {
pub fn append<N: AsRef<DomainNameSlice>>(&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<DomainNameBuf> {
Ok(self.clone())
}
fn to_cow(&self) -> Result<Cow<DomainNameSlice>> {
Ok(Cow::Borrowed(&self))
}
fn push_buf<B: BytesBuf>(&self, buf: &mut B) -> Result<()> {
self.deref().push_buf(buf)
}
fn push_buf_compressed<B: BytesBuf>(&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<DomainName> for DomainNameBuf {
fn borrow(&self) -> &DomainName {
impl Borrow<DomainNameSlice> for DomainNameBuf {
fn borrow(&self) -> &DomainNameSlice {
self.deref()
}
}
impl AsRef<DomainName> for DomainNameBuf {
fn as_ref(&self) -> &DomainName { self }
impl AsRef<DomainNameSlice> 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<Cow<'a, DomainName>> {
pub fn decompress(&self) -> Result<Cow<'a, DomainNameSlice>> {
// 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<DomainNameBuf> {
self.to_owned()
}
fn to_cow(&self) -> Result<Cow<DomainNameSlice>> {
self.decompress()
}
fn push_buf<O: BytesBuf>(&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<DomainName> + ?Sized> PartialEq<T> for WireDomainName<'a>
impl<'a, T: AsRef<DomainNameSlice> + ?Sized> PartialEq<T> for CompactDomainName<'a>
{
fn eq(&self, other: &T) -> bool {
other.as_ref().eq(self)
}
}
impl<'a, T: AsRef<DomainName> + ?Sized> PartialOrd<T> for WireDomainName<'a>
impl<'a, T: AsRef<DomainNameSlice> + ?Sized> PartialOrd<T> for CompactDomainName<'a>
{
fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
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<Cow<'a, DomainName>> {
WireDomainName::new(self.slice, self.context).decompress()
pub fn as_name(&self) -> Result<Cow<'a, DomainNameSlice>> {
CompactDomainName::new(self.slice, self.context).decompress()
}
}
impl<'a> Iterator for WireIter<'a> {
impl<'a> Iterator for CompactIter<'a> {
type Item = Result<Label<'a>>;
fn next(&mut self) -> Option<Self::Item> {
@@ -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<O: BytesBuf>(&self, o: &mut O) -> Result<()>;
fn push_buf_compressed<O: BytesBuf>(&self, o: &mut O) -> Result<()>;
}
//------------ Error and Result ---------------------------------------------
#[derive(Clone, Debug, PartialEq)]
+42 -100
View File
@@ -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<N: DomainName> {
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<DomainNameBuf>;
type CompactQuestion<'a> = Question<CompactDomainName<'a>>;
//--- Common functions and methods
impl<N: DomainName> Question<N> {
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<B: BytesBuf>(&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<QuestionBuf> {
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<Cow<DomainName>> {
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<B: BytesBuf>(&self, buf: &mut B) -> Result<()> {
try!(self.qname.push_buf(buf));
pub fn push_buf<B: BytesBuf>(&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<B: BytesBuf>(&self, buf: &mut B) -> Result<()>;
}
impl<'a> BuildQuestion for (&'a DomainName, u16, u16) {
fn push_buf<B: BytesBuf>(&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<DomainNameBuf> {
fn default() -> Self {
Question { qname: DomainNameBuf::new(), qtype: RRType::A,
qclass: Class::IN }
}
}
//--- Addtional functions and methods for compact questions
impl<'a> Question<CompactDomainName<'a>> {
/// 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 ---------------------------------------------
+93
View File
@@ -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<B: BytesBuf>(&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<C>(&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<B: BytesBuf>(&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<Option<Self>> {
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::<A>(f),
RRType::NS => self.fmt::<NS<CompactDomainName<'a>>>(f),
_ => "...".fmt(f)
}
}
}
+2
View File
@@ -1,4 +1,6 @@
//! Resource data handling.
pub mod traits;
pub mod generic;
pub mod rfc1035;
+43 -30
View File
@@ -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<B: BytesBuf>(&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<Self> {
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<N: DomainName> {
nsdname: N
}
impl<'a> NS<'a> {
pub fn new(nsdname: Cow<'a, DomainName>) -> Self {
impl<N: DomainName> NS<N> {
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<N> {
fn rtype() -> RRType { RRType::NS }
fn push_buf<B: BytesBuf>(&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<CompactDomainName<'a>> {
fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result<Self> {
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<N: DomainName> fmt::Display for NS<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.nsdname.fmt(f)
}
}
+68 -23
View File
@@ -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<B: BytesBuf>(&self, buf: &mut B) -> Result<()>;
}
pub trait RecordDataSlice<'a>: Sized {
type Owned: BuildRecordData;
fn parse(rtype: u16, rdata: &'a[u8], context: &'a [u8])
-> Result<Option<Self>>;
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<Option<Self>>;
}
//------------ 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<B: BytesBuf>(&self, buf: &mut B) -> Result<()>;
fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result<Self>;
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<Self>`.
fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result<Self>;
}
impl<'a, C: ConcreteRecordData<'a>> RecordData for C {
fn rtype(&self) -> RRType {
Self::rtype()
}
fn push_buf<B: BytesBuf>(&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<Option<Self>> {
if rtype != Self::rtype() { Ok(None) }
else { Ok(Some(try!(Self::parse(rdata, context)))) }
}
fn to_owned(&self) -> Self {
self.to_owned()
}
}
+42 -108
View File
@@ -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<D: BuildRecordData> {
name: DomainNameBuf,
pub struct Record<N: DomainName, D: RecordData> {
name: N,
rclass: Class,
ttl: u32,
rdata: D,
rdata: D
}
impl<D: BuildRecordData> RecordBuf<D> {
/// Creates a new empty record.
pub fn new<N: AsRef<DomainName>>(name: &N, rclass: Class, ttl: u32,
rdata: D) -> Self {
RecordBuf { name: name.as_ref().to_owned(), rclass: rclass, ttl: ttl,
rdata: rdata }
//--- Common
impl<N: DomainName, D: RecordData> Record<N, D> {
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<D: BuildRecordData> BuildRecord for RecordBuf<D> {
fn push_buf<B: BytesBuf>(&self, buf: &mut B) -> Result<()> {
pub fn push_buf<B: BytesBuf>(&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<D: BuildRecordData> BuildRecord for RecordBuf<D> {
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<D: RecordDataSlice<'a>>(&self)
-> Result<Option<RecordBuf<D::Owned>>> {
let rdata = match try!(self.rdata::<D>()) {
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<D: RecordDataSlice<'a>>(&self) -> Result<Option<D>> {
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<Cow<DomainName>> {
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<B: BytesBuf>(&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<CompactDomainName<'a>, D> {
/// Splits a record from the front of a bytes slice.
///
pub fn split_from(slice: &'a[u8], context: &'a[u8])
-> Result<(Option<Self>, &'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<B: BytesBuf>(&self, buf: &mut B) -> Result<()>;
}