mirror of
https://github.com/NLnetLabs/domain.git
synced 2026-10-01 14:15:00 +02:00
Rework record creation; add generic record data.
This commit is contained in:
+3
-3
@@ -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
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 { }
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 ---------------------------------------------
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
//! Resource data handling.
|
||||
|
||||
pub mod traits;
|
||||
pub mod generic;
|
||||
|
||||
pub mod rfc1035;
|
||||
|
||||
+43
-30
@@ -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
@@ -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
@@ -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<()>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user