Rewrite everything. Again.

This commit is contained in:
Martin Hoffmann
2016-03-22 16:18:15 +01:00
parent 867506811f
commit e8c3e6fff2
31 changed files with 2776 additions and 2322 deletions
+287
View File
@@ -0,0 +1,287 @@
//! Building of wire-format DNS data.
use std::collections::HashMap;
use std::fmt;
use std::mem;
use std::ptr;
use super::error::{ComposeError, ComposeResult};
use super::name::{DName, DNameSlice, Label, OwnedDName};
//------------ ComposeBytes ---------------------------------------------------
/// A trait for composing a DNS wire format message.
///
/// Messages are created by pushing data to the end of the message.
/// However, in order to avoid having to preassemble length-value parts of
/// the message such as record data, there is an option to update previously
/// written data.
pub trait ComposeBytes: Sized + fmt::Debug {
type Pos: Copy + fmt::Debug;
//--- Appending of basic types
/// Pushes a bytes slice to the end of the builder.
fn push_bytes(&mut self, data: &[u8]) -> ComposeResult<()>;
/// Pushes placeholder bytes to the end of the target.
fn push_empty(&mut self, len: usize) -> ComposeResult<()>;
/// Pushes a single octet to the end of the builder.
fn push_u8(&mut self, data: u8) -> ComposeResult<()> {
let bytes: [u8; 1] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes)
}
/// Pushes an unsigned 16-bit word to the end of the builder.
///
/// The word is converted to network byte order before writing if
/// necessary.
fn push_u16(&mut self, data: u16) -> ComposeResult<()> {
let data = data.to_be();
let bytes: [u8; 2] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes)
}
/// Pushes a unsigned 32-bit word to the end of the builder.
///
/// The word is converted to network byte order before writing if
/// necessary.
fn push_u32(&mut self, data: u32) -> ComposeResult<()> {
let data = data.to_be();
let bytes: [u8; 4] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes)
}
//--- Appending of domain names.
/// Pushes a domain name to the end of the builder.
fn push_dname<D: DName>(&mut self, name: &D) -> ComposeResult<()>;
/// Pushes a domain name to the end of the builder using compression.
fn push_dname_compressed<D: DName>(&mut self, name: &D)
-> ComposeResult<()>;
//--- Checkpoint and rollback.
/// Mark the current position as a point for truncation.
fn truncation_point(&mut self);
/// Returns whether the target has been truncated.
fn truncated(&self) -> bool;
//--- Updating of earlier data.
/// Returns the current write position of the builder.
fn pos(&self) -> Self::Pos;
/// Returns the length of data added since the given position.
fn delta(&self, pos: Self::Pos) -> usize;
/// Updates the builder starting at the given position with a bytes slice.
///
/// This method panics if the bytes slice is longer than the data
/// assembled since the given write position.
fn update_bytes(&mut self, pos: Self::Pos, data: &[u8])
-> ComposeResult<()>;
/// Updates the octet at the given write position.
///
/// This method panics if there is no data at the given write position.
fn update_u8(&mut self, pos: Self::Pos, data: u8)
-> ComposeResult<()> {
let bytes: [u8; 1] = unsafe { mem::transmute(data) };
self.update_bytes(pos, &bytes)
}
/// Updates an unsigned 16-bit word starting at the given write position.
///
/// This method panics if there aren’t two octets following the write
/// position.
fn update_u16(&mut self, pos: Self::Pos, data: u16)
-> ComposeResult<()> {
let data = data.to_be();
let bytes: [u8; 2] = unsafe { mem::transmute(data) };
self.update_bytes(pos, &bytes)
}
/// Updates an unsigned 32-bit word starting at the given write position.
///
/// This method panics if there aren’t four octets following the write
/// position.
fn update_u32(&mut self, pos: Self::Pos, data: u32)
-> ComposeResult<()> {
let data = data.to_be();
let bytes: [u8; 4] = unsafe { mem::transmute(data) };
self.update_bytes(pos, &bytes)
}
}
//------------ ComposeVec -----------------------------------------------------
/// A compose target based on a simple vector.
#[derive(Clone, Debug)]
pub struct ComposeVec {
vec: Vec<u8>,
start: usize,
maxlen: Option<usize>,
checkpoint: Option<usize>,
truncated: bool,
compress: Option<HashMap<OwnedDName, u16>>,
}
impl ComposeVec {
pub fn new(maxlen: Option<usize>, compress: bool) -> ComposeVec {
ComposeVec::with_vec(Vec::new(), maxlen, compress)
}
pub fn with_vec(vec: Vec<u8>, maxlen: Option<usize>, compress: bool)
-> ComposeVec {
let start = vec.len();
ComposeVec {
vec: Vec::new(),
start: start,
maxlen: maxlen,
checkpoint: None,
truncated: false,
compress: if compress { Some(HashMap::new()) }
else { None }
}
}
pub fn finish(self) -> Vec<u8> {
self.vec
}
}
impl ComposeVec {
fn keep_pushing(&mut self, len: usize) -> ComposeResult<()> {
if self.truncated { return Err(ComposeError::SizeExceeded) }
else if let Some(maxlen) = self.maxlen {
if maxlen < self.vec.len() + len {
self.checkpoint.map(|len| self.vec.truncate(len));
self.truncated = true;
return Err(ComposeError::SizeExceeded)
}
}
Ok(())
}
fn push_dname_simple<D: DName>(&mut self, name: &D) -> ComposeResult<()> {
for label in try!(name.to_cow()).iter() {
try!(label.compose(self))
}
Ok(())
}
fn compress_pos(&self) -> usize {
self.vec.len() - self.start
}
fn add_compress_target(&mut self, name: OwnedDName, pos: usize) {
if let Some(ref mut compress) = self.compress {
if pos <= ::std::u16::MAX as usize {
let _ = compress.insert(name, pos as u16);
}
}
}
fn get_compress_target(&self, name: &DNameSlice) -> Option<u16> {
if let Some(ref compress) = self.compress {
compress.get(name).map(|v| *v)
}
else { None }
}
}
impl ComposeBytes for ComposeVec {
type Pos = usize;
fn push_bytes(&mut self, data: &[u8]) -> ComposeResult<()> {
try!(self.keep_pushing(data.len()));
self.vec.extend(data);
Ok(())
}
fn push_empty(&mut self, len: usize) -> ComposeResult<()> {
try!(self.keep_pushing(len));
let len = self.vec.len() + len;
self.vec.resize(len, 0);
Ok(())
}
fn push_dname<D: DName>(&mut self, name: &D) -> ComposeResult<()> {
if self.compress.is_some() {
let name = try!(name.to_owned());
let pos = self.compress_pos();
try!(self.push_dname_simple(&name));
self.add_compress_target(name, pos);
Ok(())
}
else {
self.push_dname_simple(name)
}
}
fn push_dname_compressed<D: DName>(&mut self, name: &D)
-> ComposeResult<()> {
if self.compress.is_some() {
let name = try!(name.to_cow());
let mut iter = name.iter();
loop {
let name = iter.as_name();
if let Some(pos) = self.get_compress_target(name) {
try!(Label::compose_compressed(self, pos));
break;
}
let label = match iter.next() {
Some(x) => x, None => break
};
let pos = self.compress_pos();
try!(label.compose(self));
self.add_compress_target(name.to_owned(), pos);
}
Ok(())
}
else {
self.push_dname_simple(name)
}
}
fn truncation_point(&mut self) {
self.checkpoint = Some(self.vec.len())
}
fn truncated(&self) -> bool {
self.truncated
}
fn pos(&self) -> Self::Pos {
self.vec.len()
}
fn delta(&self, pos: Self::Pos) -> usize {
self.vec.len().checked_sub(pos).unwrap()
}
fn update_bytes(&mut self, pos: Self::Pos, data: &[u8])
-> ComposeResult<()> {
if pos + data.len() > self.vec.len() {
panic!("composer update overrun")
}
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(),
self.vec[pos..pos + data.len()].as_mut_ptr(),
data.len())
}
Ok(())
}
}
+122
View File
@@ -0,0 +1,122 @@
//! Errors and results
//!
//! There are three different pairs of errors and results related to the
//! three different operations that can fail:
//!
//! `ParseError` and `ParseResult` are used when parsing DNS data from its
//! wire-format.
//!
//! `ComposeError` and `ComposeResult` are used when composing DNS wire-format
//! data.
//!
//! `FromStrError` and `FromStrResult` are used when converting data from
//! strings.
use std::error::Error;
use std::fmt;
//------------ ComposeError and ComposeResult -------------------------------
#[derive(Clone, Debug)]
pub enum ComposeError {
SizeExceeded,
Overflow,
ParseError(ParseError),
}
impl Error for ComposeError {
fn description(&self) -> &str {
use self::ComposeError::*;
match *self {
SizeExceeded => "message size has been exceeded",
Overflow => "a counter has overflowed",
ParseError(ref error) => error.description(),
}
}
}
impl From<ParseError> for ComposeError {
fn from(error: ParseError) -> ComposeError {
ComposeError::ParseError(error)
}
}
impl fmt::Display for ComposeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
pub type ComposeResult<T> = Result<T, ComposeError>;
//------------ ParseError and ParseResult -----------------------------------
#[derive(Clone, Debug)]
pub enum ParseError {
UnexpectedEnd,
UnknownLabel,
UnknownType,
CompressedLabel,
}
impl Error for ParseError {
fn description(&self) -> &str {
use self::ParseError::*;
match *self {
UnexpectedEnd => "unexpected end of data",
UnknownLabel => "unknown label type in domain name",
UnknownType => "unknown type",
CompressedLabel => "a compressed label was encountered",
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
pub type ParseResult<T> = Result<T, ParseError>;
//------------ FromStrError and FromStrResult -------------------------------
#[derive(Clone, Debug)]
pub enum FromStrError {
UnexpectedEnd,
LongLabel,
IllegalEscape,
IllegalCharacter,
UnknownType,
UnknownClass,
}
impl Error for FromStrError {
fn description(&self) -> &str {
use self::FromStrError::*;
match *self {
UnexpectedEnd => "unexpected end of input",
LongLabel => "domain name label with more than 63 octets",
IllegalEscape => "illegal escape sequence",
IllegalCharacter => "illegal character",
UnknownType => "unknown type",
UnknownClass => "unknown class",
}
}
}
impl fmt::Display for FromStrError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
}
}
pub type FromStrResult<T> = Result<T, FromStrError>;
+54
View File
@@ -0,0 +1,54 @@
//! The flavors of DNS data.
//!
//! Because of the various types of domain names, all DNS data comes
//! in one of three flavors: it can be `Owned`, that is, entirely
//! self-contained; `Ref` when its data references an underlying bytes
//! slice; `Lazy` when its data references an underlying DNS message and
//! domain names can be compressed.
//!
//! This module defines the `Flavor` trait for referencing these three
//! flavors as well as the actual flavors as types.
use std::marker::PhantomData;
use super::name;
use super::nest;
/// The trait for the three flavors of DNS data.
///
/// This trait doesn’t actually define any methods but rather only collects
/// the associated types for each flavor.
pub trait Flavor<'a>: Sized {
type DName: name::DName;
type Nest: nest::Nest<'a, Self>;
}
/// The flavor for owned DNS data.
pub struct Owned;
impl<'a> Flavor<'a> for Owned {
type DName = name::OwnedDName;
type Nest = nest::OwnedNest;
}
/// The flavor for DNS data referencing an underlying bytes slice.
pub struct Ref<'a> {
marker: PhantomData<&'a u8>
}
impl<'a> Flavor<'a> for Ref<'a> {
type DName = name::DNameRef<'a>;
type Nest = nest::NestRef<'a>;
}
/// The flavor for DNS data referencing an underlying DNS message.
pub struct Lazy<'a> {
marker: PhantomData<&'a u8>
}
impl<'a> Flavor<'a> for Lazy<'a> {
type DName = name::LazyDName<'a>;
type Nest = nest::LazyNest<'a>;
}
+68 -30
View File
@@ -13,7 +13,7 @@
//!
use std::mem;
use super::bytes::{BytesSlice, Error, Result};
use super::error::{ComposeError, ComposeResult};
use super::iana::{Opcode, Rcode};
@@ -21,7 +21,7 @@ use super::iana::{Opcode, Rcode};
/// The first part of the header of a DNS message.
///
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct Header {
inner: [u8; 4]
}
@@ -39,16 +39,6 @@ impl Header {
Header { inner: [0; 4] }
}
/// Creates a header reference from the given slice.
///
/// Returns the header reference and the remainder of the slice. Or
/// an error if the slice is to short.
///
pub fn split_from(slice: &[u8]) -> Result<(&Header, &[u8])> {
let (left, right) = try!(slice.split_bytes(mem::size_of::<Self>()));
Ok((unsafe { Self::from_message(left) }, right))
}
/// Creates a header reference from a bytes slice of a message.
///
/// This function is unsafe as it assumes the bytes slice to have the
@@ -183,7 +173,7 @@ impl Header {
/// The section count part of the header of a DNS message.
///
#[derive(Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct HeaderCounts {
inner: [u8; 8]
}
@@ -196,14 +186,6 @@ impl HeaderCounts {
HeaderCounts { inner: [0; 8] }
}
/// Creates a reference from the given slice.
///
/// Returns the reference and the remainder of the slice.
pub fn split_from(slice: &[u8]) -> Result<(&HeaderCounts, &[u8])> {
let (left, right) = try!(slice.split_bytes(mem::size_of::<Self>()));
Ok((unsafe { mem::transmute(left.as_ptr()) }, right))
}
/// Creates a reference from the bytes slice of a message.
///
/// This function is unsafe as it assumes the bytes slice to have the
@@ -243,7 +225,7 @@ impl HeaderCounts {
}
/// Increase the QDCOUNT field.
pub fn inc_qdcount(&mut self, inc: u16) -> Result<()> {
pub fn inc_qdcount(&mut self, inc: u16) -> ComposeResult<()> {
self.inc_u16(0, inc)
}
@@ -258,7 +240,7 @@ impl HeaderCounts {
}
/// Increases the ANCOUNT field.
pub fn inc_ancount(&mut self, inc: u16) -> Result<()> {
pub fn inc_ancount(&mut self, inc: u16) -> ComposeResult<()> {
self.inc_u16(2, inc)
}
@@ -273,7 +255,7 @@ impl HeaderCounts {
}
/// Increases the NSCOUNT field.
pub fn inc_nscount(&mut self, inc: u16) -> Result<()> {
pub fn inc_nscount(&mut self, inc: u16) -> ComposeResult<()> {
self.inc_u16(4, inc)
}
@@ -288,7 +270,7 @@ impl HeaderCounts {
}
/// Increases the ARCOUNT field.
pub fn inc_arcount(&mut self, inc: u16) -> Result<()> {
pub fn inc_arcount(&mut self, inc: u16) -> ComposeResult<()> {
self.inc_u16(6, inc)
}
@@ -331,10 +313,10 @@ impl HeaderCounts {
self.inner[offset + 1] = value as u8;
}
fn inc_u16(&mut self, offset: usize, inc: u16) -> Result<()> {
fn inc_u16(&mut self, offset: usize, inc: u16) -> ComposeResult<()> {
let value = match self.get_u16(offset).checked_add(inc) {
Some(value) => value,
None => return Err(Error::Overflow),
None => return Err(ComposeError::Overflow),
};
self.set_u16(offset, value);
Ok(())
@@ -346,9 +328,65 @@ impl HeaderCounts {
/// The complete header of a DNS message.
///
/// Currently, this type is only used to conveniently get the size of the
/// entire header.
pub type FullHeader = [u8; 12];
#[derive(Clone, Debug, PartialEq)]
pub struct FullHeader {
inner: [u8; 12]
}
/// # Creation and Conversion
///
impl FullHeader {
/// Creates a new empty header.
pub fn new() -> FullHeader {
FullHeader { inner: [0; 12] }
}
/// Creates a reference from the bytes slice of a message.
///
/// This function is unsafe as it assumes the bytes slice to have the
/// correct length.
pub unsafe fn from_message(s: &[u8]) -> &FullHeader {
mem::transmute(s.as_ptr())
}
/// Creates a mutable reference from the bytes slice of a message.
///
/// This function is unsafe as it assumes the bytes slice to have the
/// correct length.
pub unsafe fn from_message_mut(s: &mut [u8]) -> &mut FullHeader {
mem::transmute(s.as_ptr())
}
/// Returns the underlying bytes slice.
pub fn as_bytes(&self) -> &[u8] {
&self.inner
}
}
/// # Access to Header and Dounts
///
impl FullHeader {
/// Returns a reference to the header.
pub fn header(&self) -> &Header {
unsafe { Header::from_message(&self.inner) }
}
/// Returns a mutable reference to the header.
pub fn header_mut(&mut self) -> &mut Header {
unsafe { Header::from_message_mut(&mut self. inner) }
}
/// Returns a reference to the header counts.
pub fn counts(&self) -> &HeaderCounts {
unsafe { HeaderCounts::from_message(&self.inner) }
}
/// Returns a mutable reference to the header counts.
pub fn counts_mut(&mut self) -> &mut HeaderCounts {
unsafe { HeaderCounts::from_message_mut(&mut self.inner) }
}
}
//============ Testing ======================================================
+17 -46
View File
@@ -1,12 +1,9 @@
//! DNS CLASSes.
use std::convert;
use std::error;
use std::fmt;
use std::num;
use std::result;
use std::str;
use super::super::bytes::BytesBuf;
use super::super::error::{FromStrError, FromStrResult};
/// DNS CLASSes.
@@ -62,10 +59,6 @@ impl Class {
Int(value) => value
}
}
pub fn push_buf<B: BytesBuf>(self, buf: &mut B) {
buf.push_u16(self.to_int());
}
}
impl convert::From<u16> for Class {
@@ -74,10 +67,16 @@ impl convert::From<u16> for Class {
}
}
impl str::FromStr for Class {
type Err = ParseError;
impl convert::From<Class> for u16 {
fn from(value: Class) -> u16 {
value.to_int()
}
}
fn from_str(s: &str) -> ParseResult<Self> {
impl str::FromStr for Class {
type Err = FromStrError;
fn from_str(s: &str) -> FromStrResult<Self> {
use std::ascii::AsciiExt;
use self::Class::*;
@@ -90,14 +89,18 @@ impl str::FromStr for Class {
if let Some((n, _)) = s.char_indices().nth(5) {
let (l, r) = s.split_at(n);
if l.eq_ignore_ascii_case("CLASS") {
Ok(Int(try!(u16::from_str_radix(r, 10))))
let value = match u16::from_str_radix(r, 10) {
Ok(x) => x,
Err(..) => return Err(FromStrError::UnknownClass)
};
Ok(Int(value))
}
else {
Err(ParseError::UnknownClass)
Err(FromStrError::UnknownClass)
}
}
else {
Err(ParseError::UnknownClass)
Err(FromStrError::UnknownClass)
}
}
}
@@ -140,35 +143,3 @@ impl PartialEq<Class> for u16 {
impl Eq for Class { }
//------------ ParseError and ParseResult -----------------------------------
#[derive(Debug, Clone, PartialEq)]
pub enum ParseError {
UnknownClass,
}
impl error::Error for ParseError {
fn description(&self) -> &str {
match *self {
ParseError::UnknownClass => "unknown class",
}
}
}
impl convert::From<num::ParseIntError> for ParseError {
fn from(_: num::ParseIntError) -> Self {
ParseError::UnknownClass
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
self.description().fmt(f)
}
}
pub type ParseResult<T> = result::Result<T, ParseError>;
+15 -45
View File
@@ -2,12 +2,9 @@
//!
use std::convert;
use std::error;
use std::fmt;
use std::num;
use std::result;
use std::str;
use super::super::bytes::BytesBuf;
use super::super::error::{FromStrError, FromStrResult};
/// Resource Record Types.
@@ -586,10 +583,6 @@ impl RRType {
Int(value) => value
}
}
pub fn push_buf<B: BytesBuf>(self, buf: &mut B) {
buf.push_u16(self.to_int())
}
}
impl convert::From<u16> for RRType {
@@ -598,11 +591,16 @@ impl convert::From<u16> for RRType {
}
}
impl convert::From<RRType> for u16 {
fn from(value: RRType) -> u16 {
value.to_int()
}
}
impl str::FromStr for RRType {
type Err = ParseError;
type Err = FromStrError;
fn from_str(s: &str) -> ParseResult<Self> {
fn from_str(s: &str) -> FromStrResult<Self> {
use std::ascii::AsciiExt;
use self::RRType::*;
@@ -694,14 +692,18 @@ impl str::FromStr for RRType {
if let Some((n, _)) = s.char_indices().nth(4) {
let (l, r) = s.split_at(n);
if l.eq_ignore_ascii_case("TYPE") {
Ok(Int(try!(u16::from_str_radix(r, 10))))
let value = match u16::from_str_radix(r, 10) {
Ok(x) => x,
Err(..) => return Err(FromStrError::UnknownType)
};
Ok(Int(value))
}
else {
Err(ParseError::UnknownType)
Err(FromStrError::UnknownType)
}
}
else {
Err(ParseError::UnknownType)
Err(FromStrError::UnknownType)
}
}
}
@@ -823,35 +825,3 @@ impl PartialEq<RRType> for u16 {
impl Eq for RRType { }
//------------ ParseError and ParseResult -----------------------------------
#[derive(Debug, Clone, PartialEq)]
pub enum ParseError {
UnknownType,
}
impl error::Error for ParseError {
fn description(&self) -> &str {
match *self {
ParseError::UnknownType => "unknown type",
}
}
}
impl convert::From<num::ParseIntError> for ParseError {
fn from(_: num::ParseIntError) -> Self {
ParseError::UnknownType
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
self.description().fmt(f)
}
}
pub type ParseResult<T> = result::Result<T, ParseError>;
+470
View File
@@ -0,0 +1,470 @@
//! DNS messages.
use std::marker::PhantomData;
use std::mem;
use super::compose::ComposeBytes;
use super::error::{ComposeError, ComposeResult, ParseResult};
use super::flavor::{self, Flavor};
use super::header::{Header, HeaderCounts, FullHeader};
use super::nest::{self, Nest};
use super::parse::ParseBytes;
use super::question::{ComposeQuestion, Question};
use super::rdata::{GenericRecordData, RecordData};
use super::record::{ComposeRecord, Record};
//============ Disecting Existing Messages ==================================
//============ Message ======================================================
/// A DNS message.
#[derive(Clone, Debug)]
pub struct Message<'a, F: Flavor<'a>> {
nest: F::Nest
}
pub type OwnedMessage<'a> = Message<'a, flavor::Owned>;
pub type MessageRef<'a> = Message<'a, flavor::Ref<'a>>;
pub type LazyMessage<'a> = Message<'a, flavor::Lazy<'a>>;
/// # Creation and Conversion
///
impl<'a, F: Flavor<'a>> Message<'a, F> {
/// Creates a message from a nest.
pub fn from_nest(nest: F::Nest) -> Self {
Message { nest: nest }
}
}
impl<'a> Message<'a, flavor::Ref<'a>> {
pub fn from_bytes(bytes: &'a [u8]) -> Self {
Message::from_nest(nest::NestRef::from_bytes(bytes))
}
}
impl<'a> Message<'a, flavor::Lazy<'a>> {
pub fn from_bytes(bytes: &'a [u8]) -> Self {
Message::from_nest(nest::LazyNest::new(bytes, bytes))
}
}
// # Header Access
//
impl<'a, F: Flavor<'a>> Message<'a, F> {
/// Returns a reference to the message header.
pub fn header<'b: 'a>(&'b self) -> &'a Header {
unsafe { Header::from_message(self.nest.as_slice()) }
}
/// Returns a reference to the header counts of the message.
pub fn counts<'b: 'a>(&'b self) -> &'a HeaderCounts {
unsafe { HeaderCounts::from_message(self.nest.as_slice()) }
}
/// Returns an iterator over the question section
pub fn question<'b: 'a>(&'b self) -> QuestionSection<'a, F> {
let mut parser = self.nest.parser();
parser.skip(mem::size_of::<FullHeader>()).unwrap(); // XXX Hmm.
QuestionSection::new(parser, (*self.counts()).clone())
}
}
//------------ QuestionSection ----------------------------------------------
#[derive(Clone, Debug)]
pub struct QuestionSection<'a, F: Flavor<'a>> {
parser: <F::Nest as Nest<'a, F>>::Parser,
counts: HeaderCounts,
count: u16
}
impl<'a, F: Flavor<'a>> QuestionSection<'a, F> {
fn new(parser: <F::Nest as Nest<'a, F>>::Parser, counts: HeaderCounts)
-> Self {
let count = counts.qdcount();
QuestionSection { parser: parser, counts: counts, count: count }
}
pub fn iter(&mut self) -> &mut Self {
self
}
/// Continues to the answer section.
pub fn answer(mut self) -> ParseResult<AnswerSection<'a, F>> {
for question in self.iter() {
if let Err(e) = question {
return Err(e)
}
}
Ok(AnswerSection::new(self.parser, self.counts))
}
}
impl<'a, F: Flavor<'a>> Iterator for QuestionSection<'a, F> {
type Item = ParseResult<Question<'a, F>>;
fn next(&mut self) -> Option<Self::Item> {
if self.count == 0 { return None }
Some(Question::parse(&mut self.parser)
.map(|res| { self.count -= 1; res }))
}
}
//------------ AnswerSection ------------------------------------------------
/// The answer section of a message.
#[derive(Clone, Debug)]
pub struct AnswerSection<'a, F: Flavor<'a>> {
parser: <F::Nest as Nest<'a, F>>::Parser,
counts: HeaderCounts,
}
impl<'a, F: Flavor<'a>> AnswerSection<'a, F> {
fn new(parser: <F::Nest as Nest<'a, F>>::Parser, counts: HeaderCounts)
-> Self {
AnswerSection { parser: parser, counts: counts }
}
pub fn iter<D: RecordData<'a, F>>(&self) -> RecordIter<'a, F, D> {
RecordIter::new(self.parser.clone(), self.counts.ancount())
}
pub fn authority(self) -> ParseResult<AuthoritySection<'a, F>> {
let mut iter = self.iter::<GenericRecordData<'a, F>>();
try!(iter.exhaust());
Ok(AuthoritySection::new(iter.parser, self.counts))
}
}
//------------ AuthoritySection ---------------------------------------------
/// The authority section of a message.
#[derive(Clone, Debug)]
pub struct AuthoritySection<'a, F: Flavor<'a>> {
parser: <F::Nest as Nest<'a, F>>::Parser,
counts: HeaderCounts,
}
impl<'a, F: Flavor<'a>> AuthoritySection<'a, F> {
fn new(parser: <F::Nest as Nest<'a, F>>::Parser, counts: HeaderCounts)
-> Self {
AuthoritySection { parser: parser, counts: counts }
}
pub fn iter<D: RecordData<'a, F>>(&self) -> RecordIter<'a, F, D> {
RecordIter::new(self.parser.clone(), self.counts.nscount())
}
pub fn additional(self) -> ParseResult<AdditionalSection<'a, F>> {
let mut iter = self.iter::<GenericRecordData<'a, F>>();
try!(iter.exhaust());
Ok(AdditionalSection::new(iter.parser, self.counts))
}
}
//------------ AdditionalSection --------------------------------------------
/// The additional section of a message.
#[derive(Clone, Debug)]
pub struct AdditionalSection<'a, F: Flavor<'a>> {
parser: <F::Nest as Nest<'a, F>>::Parser,
counts: HeaderCounts,
}
impl<'a, F: Flavor<'a>> AdditionalSection<'a, F> {
fn new(parser: <F::Nest as Nest<'a, F>>::Parser, counts: HeaderCounts)
-> Self {
AdditionalSection { parser: parser, counts: counts }
}
pub fn iter<D: RecordData<'a, F>>(&self) -> RecordIter<'a, F, D> {
RecordIter::new(self.parser.clone(), self.counts.ancount())
}
}
//------------ RecordIter ---------------------------------------------------
/// An iterator over the records in one of a record section.
#[derive(Clone, Debug)]
pub struct RecordIter<'a, F: Flavor<'a>, D: RecordData<'a, F>> {
parser: <F::Nest as Nest<'a, F>>::Parser,
count: u16,
marker: PhantomData<D>
}
impl<'a, F: Flavor<'a>, D: RecordData<'a, F>> RecordIter<'a, F, D> {
fn new(parser: <F::Nest as Nest<'a, F>>::Parser, count: u16) -> Self {
RecordIter { parser: parser, count: count, marker: PhantomData }
}
pub fn iter(&mut self) -> &mut Self { self }
fn exhaust(&mut self) -> ParseResult<()> {
for record in self.iter() {
if let Err(e) = record {
return Err(e)
}
}
Ok(())
}
fn step(&mut self) -> ParseResult<Option<Record<'a, F, D>>> {
Record::parse(&mut self.parser).map(|res| { self.count -= 1; res })
}
}
impl<'a, F, D> Iterator for RecordIter<'a, F, D>
where F: Flavor<'a>, D: RecordData<'a, F> {
type Item = ParseResult<Record<'a, F, D>>;
fn next(&mut self) -> Option<Self::Item> {
if self.count == 0 { return None }
loop {
match self.step() {
Ok(Some(record)) => return Some(Ok(record)),
Ok(None) => (),
Err(e) => return Some(Err(e)),
}
}
}
}
//============ Building New Message =========================================
//------------ MessageBuilder -----------------------------------------------
/// A builder for constructing a DNS message.
#[derive(Clone, Debug)]
pub struct MessageBuilder<C: ComposeBytes> {
target: MessageTarget<C>
}
impl<C: ComposeBytes> MessageBuilder<C> {
/// Creates a new message builder.
pub fn new(target: C) -> ComposeResult<Self> {
MessageTarget::new(target)
.map(|target| MessageBuilder { target: target })
}
pub fn header(&self) -> &Header {
self.target.header()
}
pub fn header_mut(&mut self) -> &mut Header {
self.target.header_mut()
}
pub fn finish(self) -> ComposeResult<C> {
self.target.finish()
}
pub fn question(self) -> QuestionBuilder<C> {
QuestionBuilder::new(self.target)
}
}
//------------ QuestionBuilder ----------------------------------------------
#[derive(Clone, Debug)]
pub struct QuestionBuilder<C: ComposeBytes> {
target: MessageTarget<C>
}
impl<C: ComposeBytes> QuestionBuilder<C> {
fn new(target: MessageTarget<C>) -> Self {
QuestionBuilder { target: target }
}
pub fn header(&self) -> &Header {
self.target.header()
}
pub fn header_mut(&mut self) -> &mut Header {
self.target.header_mut()
}
pub fn push<Q: ComposeQuestion>(&mut self, question: &Q)
-> ComposeResult<()> {
self.target.push(|target| question.compose(target),
|counts| counts.inc_qdcount(1))
}
pub fn answer(self) -> AnswerBuilder<C> {
AnswerBuilder::new(self.target)
}
pub fn finish(self) -> ComposeResult<C> {
self.target.finish()
}
}
//------------ AnswerBuilder ------------------------------------------------
#[derive(Clone, Debug)]
pub struct AnswerBuilder<C: ComposeBytes> {
target: MessageTarget<C>
}
impl<C: ComposeBytes> AnswerBuilder<C> {
fn new(target: MessageTarget<C>) -> Self {
AnswerBuilder { target: target }
}
pub fn header(&self) -> &Header {
self.target.header()
}
pub fn header_mut(&mut self) -> &mut Header {
self.target.header_mut()
}
pub fn push<R: ComposeRecord>(&mut self, record: &R) -> ComposeResult<()> {
self.target.push(|target| record.compose(target),
|counts| counts.inc_ancount(1))
}
pub fn authority(self) -> AuthorityBuilder<C> {
AuthorityBuilder::new(self.target)
}
pub fn finish(self) -> ComposeResult<C> {
self.target.finish()
}
}
//------------ AuthorityBuilder ---------------------------------------------
#[derive(Clone, Debug)]
pub struct AuthorityBuilder<C: ComposeBytes> {
target: MessageTarget<C>
}
impl<C: ComposeBytes> AuthorityBuilder<C> {
fn new(target: MessageTarget<C>) -> Self {
AuthorityBuilder { target: target }
}
pub fn header(&self) -> &Header {
self.target.header()
}
pub fn header_mut(&mut self) -> &mut Header {
self.target.header_mut()
}
pub fn push<R: ComposeRecord>(&mut self, record: &R) -> ComposeResult<()> {
self.target.push(|target| record.compose(target),
|counts| counts.inc_nscount(1))
}
pub fn additional(self) -> AdditionalBuilder<C> {
AdditionalBuilder::new(self.target)
}
pub fn finish(self) -> ComposeResult<C> {
self.target.finish()
}
}
//------------ AuthorityBuilder ---------------------------------------------
#[derive(Clone, Debug)]
pub struct AdditionalBuilder<C: ComposeBytes> {
target: MessageTarget<C>
}
impl<C: ComposeBytes> AdditionalBuilder<C> {
fn new(target: MessageTarget<C>) -> Self {
AdditionalBuilder { target: target }
}
pub fn header(&self) -> &Header {
self.target.header()
}
pub fn header_mut(&mut self) -> &mut Header {
self.target.header_mut()
}
pub fn push<R: ComposeRecord>(&mut self, record: &R) -> ComposeResult<()> {
self.target.push(|target| record.compose(target),
|counts| counts.inc_nscount(1))
}
pub fn finish(self) -> ComposeResult<C> {
self.target.finish()
}
}
//------------ MessageTarget ------------------------------------------------
/// Underlying data for constructing a DNS message.
///
/// This private type does all the heavy lifting for constructing messages.
#[derive(Clone, Debug)]
struct MessageTarget<C: ComposeBytes> {
/// The underlying bytes target.
target: C,
/// The message’s header.
header: FullHeader,
/// Position in build where the message starts.
start: C::Pos,
}
impl<C: ComposeBytes> MessageTarget<C> {
fn new(mut target: C) -> ComposeResult<Self> {
let start = target.pos();
try!(target.push_empty(mem::size_of::<FullHeader>()));
Ok(MessageTarget {
target: target,
header: FullHeader::new(),
start: start
})
}
fn header(&self) -> &Header {
self.header.header()
}
fn header_mut(&mut self) -> &mut Header {
self.header.header_mut()
}
fn push<O, I>(&mut self, composeop: O, incop: I) -> ComposeResult<()>
where O: FnOnce(&mut C) -> ComposeResult<()>,
I: FnOnce(&mut HeaderCounts) -> ComposeResult<()> {
if !self.target.truncated() {
self.target.truncation_point();
match composeop(&mut self.target) {
Ok(()) => {
try!(incop(self.header.counts_mut()));
Ok(())
}
Err(ComposeError::SizeExceeded) => Ok(()),
Err(error) => Err(error)
}
}
else { Ok(()) }
}
fn finish(mut self) -> ComposeResult<C> {
self.header.header_mut().set_tc(self.target.truncated());
try!(self.target.update_bytes(self.start, self.header.as_bytes()));
Ok(self.target)
}
}
+15
View File
@@ -0,0 +1,15 @@
//! DNS data.
pub mod compose;
pub mod error;
pub mod flavor;
pub mod header;
pub mod iana;
pub mod message;
pub mod name;
pub mod nest;
pub mod question;
pub mod parse;
pub mod rdata;
pub mod record;
pub mod u8;
File diff suppressed because it is too large Load Diff
+247
View File
@@ -0,0 +1,247 @@
//! Arbitrary sequences of embedded DNS data.
use std::borrow::Borrow;
use std::fmt::Debug;
use std::ops::Deref;
use super::compose::ComposeBytes;
use super::parse::{ParseBytes, ParseFlavor, ParseLazy, SliceParser,
ContextParser};
use super::error::{ComposeResult, ParseResult};
use super::flavor::{Flavor, Owned, Ref, Lazy};
use super::rdata::RecordData;
//------------ Nest --------------------------------------------------------
/// A trait common to all nest types.
pub trait Nest<'a, F: Flavor<'a>>: Sized + Clone + Debug {
type Parser: ParseFlavor<'a, F> + Clone + Debug;
fn as_slice<'b: 'a>(&'b self) -> &'a [u8];
fn len(&self) -> usize();
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()>;
fn parser<'b: 'a>(&'b self) -> Self::Parser;
}
//------------ NestRef -----------------------------------------------------
/// A reference to a nest.
///
/// This is a thin wrapper around an actual `&[u8]` and even derefs to it.
#[derive(Clone, Debug)]
pub struct NestRef<'a> {
inner: &'a [u8]
}
impl<'a> NestRef<'a> {
pub fn from_bytes(bytes: &'a [u8]) -> Self {
NestRef { inner: bytes }
}
pub fn as_slice(&self) -> &'a [u8] {
self.inner
}
pub fn to_owned(&self) -> OwnedNest {
OwnedNest::from_bytes(self.inner)
}
pub fn parse<P: ParseBytes<'a>>(parser: &mut P, len: usize)
-> ParseResult<Self> {
Ok(NestRef { inner: try!(parser.parse_bytes(len)) })
}
}
//--- Nest
impl<'a> Nest<'a, Ref<'a>> for NestRef<'a> {
type Parser = SliceParser<'a>;
fn as_slice<'b: 'a>(&'b self) -> &'a [u8] {
self.inner
}
fn len(&self) -> usize {
self.inner.len()
}
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
target.push_bytes(self.inner)
}
fn parser<'b: 'a>(&'b self) -> SliceParser<'a> {
SliceParser::new(&self.inner)
}
}
//--- From
impl<'a> From<&'a [u8]> for NestRef<'a> {
fn from(bytes: &'a[u8]) -> NestRef<'a> {
NestRef::from_bytes(bytes)
}
}
//--- Deref, Borrow, AsRef
impl<'a> Deref for NestRef<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.inner
}
}
impl<'a> Borrow<[u8]> for NestRef<'a> {
fn borrow(&self) -> &[u8] {
self.deref()
}
}
impl<'a> AsRef<[u8]> for NestRef<'a> {
fn as_ref(&self) -> &[u8] {
self.deref()
}
}
//------------ OwnedNest ---------------------------------------------------
/// An owned nest.
///
/// This type derefs to `Vec<u8>` for all bytes slice methods.
#[derive(Clone, Debug)]
pub struct OwnedNest {
inner: Vec<u8>
}
impl OwnedNest {
pub fn new() -> Self {
OwnedNest { inner: Vec::new() }
}
pub fn from_bytes(slice: &[u8]) -> Self {
OwnedNest { inner: Vec::from(slice) }
}
pub fn parse<'a, P>(p: &mut P, len: usize) -> ParseResult<Self>
where P: ParseBytes<'a> {
Ok(try!(NestRef::parse(p, len)).to_owned())
}
pub fn as_slice(&self) -> &[u8] {
self
}
}
//--- Nest
impl<'a> Nest<'a, Owned> for OwnedNest {
type Parser = SliceParser<'a>;
fn as_slice<'b: 'a>(&'b self) -> &'a [u8] {
&self.inner
}
fn len(&self) -> usize {
self.inner.len()
}
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
target.push_bytes(&self.inner)
}
fn parser<'b: 'a>(&'b self) -> SliceParser<'a> {
SliceParser::new(&self.inner)
}
}
//--- From
impl<'a> From<&'a [u8]> for OwnedNest {
fn from(bytes: &'a [u8]) -> Self {
OwnedNest::from_bytes(bytes)
}
}
//--- Deref
impl Deref for OwnedNest {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
//------------ LazyNest ----------------------------------------------------
/// A bytes sequence possibly containing compressed domain names.
///
/// For most purposes, this is identical to `NestRef` except that it
/// carries the context for decompressing domain names around.
#[derive(Clone, Debug)]
pub struct LazyNest<'a> {
bytes: &'a [u8],
context: &'a [u8]
}
impl<'a> LazyNest<'a> {
pub fn new(bytes: &'a[u8], context: &'a[u8]) -> Self {
LazyNest { bytes: bytes, context: context }
}
pub fn parse<P: ParseLazy<'a>>(parser: &mut P, len: usize)
-> ParseResult<Self> {
Ok(LazyNest::new(try!(parser.parse_bytes(len)),
parser.context()))
}
pub fn to_owned(&self) -> OwnedNest {
OwnedNest::from_bytes(self.bytes)
}
}
//--- Nest
impl<'a> Nest<'a, Lazy<'a>> for LazyNest<'a> {
type Parser = ContextParser<'a>;
fn as_slice<'b: 'a>(&'b self) -> &'a [u8] {
self.bytes
}
fn len(&self) -> usize {
self.bytes.len()
}
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
target.push_bytes(self.bytes)
}
fn parser<'b: 'a>(&'b self) -> ContextParser<'a> {
ContextParser::new(self.bytes, self.context)
}
}
//--- Deref
impl<'a> Deref for LazyNest<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.bytes
}
}
+222
View File
@@ -0,0 +1,222 @@
//! Parsing of wire-format DNS data.
use std::mem;
use super::error::{ParseResult, ParseError};
use super::flavor::{Flavor, Owned, Ref, Lazy};
use super::name::{OwnedDName, DNameRef, LazyDName};
use super::nest::{OwnedNest, NestRef, LazyNest};
//------------ Traits -------------------------------------------------------
/// A trait for parsing simple wire-format DNS data.
pub trait ParseBytes<'a>: Sized {
/// Parses a bytes slice of a given length.
fn parse_bytes(&mut self, len: usize) -> ParseResult<&'a [u8]>;
/// Skip the next `len` bytes.
fn skip(&mut self, len: usize) -> ParseResult<()>;
/// Parses a single octet.
fn parse_u8(&mut self) -> ParseResult<u8> {
self.parse_bytes(1).map(|res| res[0])
}
/// Parses an unsigned 16-bit word.
fn parse_u16(&mut self) -> ParseResult<u16> {
self.parse_bytes(2).map(|res| {
let res: &[u8; 2] = unsafe { mem::transmute(res.as_ptr()) };
let res = unsafe { mem::transmute(*res) };
u16::from_be(res)
})
}
/// Parses an unsigned 32-bit word.
fn parse_u32(&mut self) -> ParseResult<u32> {
self.parse_bytes(4).map(|res| {
let res: &[u8; 4] = unsafe { mem::transmute(res.as_ptr()) };
let res = unsafe { mem::transmute(*res) };
u32::from_be(res)
})
}
/// Creates a sup-parser starting a the current position.
fn sub(&self) -> Self;
/// Creates a sub-parser limited to `len` bytes and advance position.
fn parse_sub(&mut self, len: usize) -> ParseResult<Self>;
/// Returns the length of the data we have seen already.
fn seen(&self) -> usize;
/// Returns the length of the data left.
fn left(&self) -> usize;
}
pub trait ParseLazy<'a>: ParseBytes<'a> {
fn context(&self) -> &'a[u8];
}
/// A trait for parsing wire-format DNS data.
///
/// While the basic types are implemented for every parser through the
/// `ParseBytesSimple` trait, not every parser can parse every kind of
/// domain name. Because of this, parsers may implement the
/// `ParseBytes` trait only for specific flavors.
pub trait ParseFlavor<'a, F: Flavor<'a>>: ParseBytes<'a> {
fn parse_name(&mut self) -> ParseResult<F::DName>;
fn parse_nest(&mut self, len: usize) -> ParseResult<F::Nest>;
}
impl<'a, P: ParseBytes<'a>> ParseFlavor<'a, Owned> for P {
fn parse_name(&mut self) -> ParseResult<OwnedDName> {
OwnedDName::parse_complete(self)
}
fn parse_nest(&mut self, len: usize) -> ParseResult<OwnedNest> {
OwnedNest::parse(self, len)
}
}
impl<'a, P: ParseBytes<'a>> ParseFlavor<'a, Ref<'a>> for P {
fn parse_name(&mut self) -> ParseResult<DNameRef<'a>> {
DNameRef::parse(self)
}
fn parse_nest(&mut self, len: usize) -> ParseResult<NestRef<'a>> {
NestRef::parse(self, len)
}
}
impl<'a> ParseFlavor<'a, Lazy<'a>> for ContextParser<'a> {
fn parse_name(&mut self) -> ParseResult<LazyDName<'a>> {
LazyDName::parse(self)
}
fn parse_nest(&mut self, len: usize) -> ParseResult<LazyNest<'a>> {
LazyNest::parse(self, len)
}
}
//------------ SliceParser --------------------------------------------------
/// A parser that operates on an arbitrary bytes slice.
#[derive(Clone, Debug)]
pub struct SliceParser<'a> {
slice: &'a [u8],
seen: usize,
}
impl<'a> SliceParser<'a> {
pub fn new(slice: &'a [u8]) -> Self {
SliceParser { slice: slice, seen: 0 }
}
fn check_len(&self, len: usize) -> ParseResult<()> {
if len > self.slice.len() {
Err(ParseError::UnexpectedEnd)
}
else {
Ok(())
}
}
}
impl<'a> ParseBytes<'a> for SliceParser<'a> {
fn parse_bytes(&mut self, len: usize) -> ParseResult<&'a [u8]> {
try!(self.check_len(len));
let (l, r) = self.slice.split_at(len);
self.slice = r;
self.seen += len;
Ok(l)
}
fn skip(&mut self, len: usize) -> ParseResult<()> {
try!(self.check_len(len));
self.slice = &self.slice[len..];
self.seen += len;
Ok(())
}
fn sub(&self) -> Self {
SliceParser { slice: self.slice, seen: 0 }
}
fn parse_sub(&mut self, len: usize) -> ParseResult<Self> {
Ok(SliceParser { slice: try!(self.parse_bytes(len)), seen: 0 })
}
fn seen(&self) -> usize {
self.seen
}
fn left(&self) -> usize {
self.slice.len()
}
}
//------------ ContextParser ------------------------------------------------
/// A parser that operates on an entire DNS message.
#[derive(Clone, Debug)]
pub struct ContextParser<'a> {
parser: SliceParser<'a>,
context: &'a [u8]
}
impl<'a> ContextParser<'a> {
pub fn new(slice: &'a[u8], context: &'a[u8]) -> Self {
ContextParser {
parser: SliceParser::new(slice),
context: context
}
}
pub fn from_message(message: &'a [u8]) -> Self {
ContextParser {
parser: SliceParser::new(message),
context: message
}
}
}
impl<'a> ParseBytes<'a> for ContextParser<'a> {
fn parse_bytes(&mut self, len: usize) -> ParseResult<&'a [u8]> {
self.parser.parse_bytes(len)
}
fn skip(&mut self, len: usize) -> ParseResult<()> {
self.parser.skip(len)
}
fn sub(&self) -> Self {
ContextParser {
parser: self.parser.sub(),
context: self.context
}
}
fn parse_sub(&mut self, len: usize) -> ParseResult<Self> {
Ok(ContextParser {
parser: try!(self.parser.parse_sub(len)),
context: self.context
})
}
fn seen(&self) -> usize {
self.parser.seen()
}
fn left(&self) -> usize {
self.parser.left()
}
}
impl<'a> ParseLazy<'a> for ContextParser<'a> {
fn context(&self) -> &'a [u8] {
self.context
}
}
+92
View File
@@ -0,0 +1,92 @@
//! A single question of a DNS message.
use super::compose::ComposeBytes;
use super::error::{ComposeResult, ParseResult};
use super::flavor::{self, Flavor};
use super::iana::{Class, RRType};
use super::name::DName;
use super::parse::ParseFlavor;
//------------ Question -----------------------------------------------------
#[derive(Clone, Debug)]
pub struct Question<'a, F: Flavor<'a>> {
qname: F::DName,
qtype: RRType,
qclass: Class,
}
pub type OwnedQuestion<'a> = Question<'a, flavor::Owned>;
pub type QuestionRef<'a> = Question<'a, flavor::Ref<'a>>;
pub type LazyQuestion<'a> = Question<'a, flavor::Lazy<'a>>;
/// # Creation and Conversion
///
impl<'a, F: Flavor<'a>> Question<'a, F> {
pub fn new(qname: F::DName, qtype: RRType, qclass: Class) -> Self {
Question { qname: qname, qtype: qtype, qclass: qclass }
}
}
/// # Element Access
///
impl<'a, F: Flavor<'a>> Question<'a, F> {
/// Returns the requested domain name.
pub fn qname(&self) -> &F::DName {
&self.qname
}
/// Returns the requested record type.
pub fn qtype(&self) -> RRType {
self.qtype
}
/// Returns the requested class.
pub fn qclass(&self) -> Class {
self.qclass
}
}
/// Parsing and Composing
///
impl<'a, F: Flavor<'a>> Question<'a, F> {
pub fn parse<P>(parser: &mut P) -> ParseResult<Self>
where P: ParseFlavor<'a, F> {
Ok(Question::new(try!(parser.parse_name()),
try!(parser.parse_u16()).into(),
try!(parser.parse_u16()).into()))
}
pub fn compose<C: ComposeBytes>(&self, target: &mut C)
-> ComposeResult<()> {
try!(target.push_dname_compressed(&self.qname));
try!(target.push_u16(self.qtype.into()));
target.push_u16(self.qclass.into())
}
}
//------------ ComposeQuestion ----------------------------------------------
/// Helper trait to allow composing questions from tuples.
pub trait ComposeQuestion {
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()>;
}
impl<'a, F: Flavor<'a>> ComposeQuestion for Question<'a, F> {
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
self.compose(target)
}
}
impl<D: DName> ComposeQuestion for (D, RRType, Class) {
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
try!(target.push_dname_compressed(&self.0));
try!(target.push_u16(self.1.into()));
target.push_u16(self.2.into())
}
}
+72
View File
@@ -0,0 +1,72 @@
//! Generic Record Data Types
use std::fmt;
use super::super::compose::ComposeBytes;
use super::super::flavor::Flavor;
use super::super::error::{ComposeResult, ParseResult};
use super::super::iana::RRType;
use super::super::nest::Nest;
use super::super::parse::ParseFlavor;
use super::traits::RecordData;
pub struct GenericRecordData<'a, F: Flavor<'a>> {
rtype: RRType,
data: F::Nest,
}
impl<'a, F: Flavor<'a>> GenericRecordData<'a, F> {
pub fn new(rtype: RRType, data: F::Nest) -> Self {
GenericRecordData { rtype: rtype, data: data }
}
pub fn rtype(&self) -> RRType { self.rtype }
pub fn data(&self) -> &F::Nest { &self.data }
/*
pub fn fmt<R: RecordData<'a, F>>(&'a self, f: &mut fmt::Formatter)
-> fmt::Result {
let mut parser = self.data.parser();
match R::parse(self.rtype, &mut parser) {
Err(..) => Ok(()),
Ok(None) => Ok(()),
Ok(Some(data)) => data.fmt(f)
}
}
*/
}
impl<'a, F: Flavor<'a>> RecordData<'a, F> for GenericRecordData<'a, F> {
fn rtype(&self) -> RRType {
self.rtype
}
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
self.data.compose(target)
}
fn parse<P>(rtype: RRType, parser: &mut P) -> ParseResult<Option<Self>>
where P: ParseFlavor<'a, F> {
let len = parser.left();
let nest = try!(parser.parse_nest(len));
Ok(Some(GenericRecordData::new(rtype, nest)))
}
}
impl<'a, F: Flavor<'a>> fmt::Display for GenericRecordData<'a, F> {
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<F>>(f),
_ => "...".fmt(f)
}
*/
"...".fmt(f)
}
}
@@ -1,5 +1,8 @@
//! Resource data handling.
pub use self::traits::RecordData;
pub use self::generic::GenericRecordData;
pub mod traits;
pub mod generic;
+93
View File
@@ -0,0 +1,93 @@
use std::fmt;
use std::net;
use super::super::compose::ComposeBytes;
use super::super::error::{ComposeResult, ParseResult};
use super::super::flavor::Flavor;
use super::super::iana::RRType;
use super::super::parse::ParseFlavor;
use super::traits::RecordData;
//------------ A ------------------------------------------------------------
#[derive(Clone, Debug)]
pub struct A {
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, F: Flavor<'a>> RecordData<'a, F> for A {
fn rtype(&self) -> RRType { RRType::A }
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
for i in self.addr.octets().iter() {
try!(target.push_u8(*i))
}
Ok(())
}
fn parse<P>(rtype: RRType, parser: &mut P) -> ParseResult<Option<Self>>
where P: ParseFlavor<'a, F> {
if rtype != RRType::A { return Ok(None) }
Ok(Some(A::new(net::Ipv4Addr::new(try!(parser.parse_u8()),
try!(parser.parse_u8()),
try!(parser.parse_u8()),
try!(parser.parse_u8())))))
}
}
impl fmt::Display for A {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.addr.fmt(f)
}
}
//------------ NS -----------------------------------------------------------
#[derive(Clone, Debug)]
pub struct NS<'a, F: Flavor<'a>> {
nsdname: F::DName
}
impl<'a, F: Flavor<'a>> NS<'a, F> {
pub fn new(nsdname: F::DName) -> Self {
NS { nsdname: nsdname }
}
pub fn nsdname(&self) -> &F::DName {
&self.nsdname
}
}
impl<'a, F: Flavor<'a>> RecordData<'a, F> for NS<'a, F> {
fn rtype(&self) -> RRType { RRType::NS }
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
target.push_dname_compressed(&self.nsdname)
}
fn parse<P>(rtype: RRType, parser: &mut P) -> ParseResult<Option<Self>>
where P: ParseFlavor<'a, F> {
if rtype != RRType::NS { return Ok(None) }
Ok(Some(NS::new(try!(parser.parse_name()))))
}
}
impl<'a, F: Flavor<'a>> fmt::Display for NS<'a, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.nsdname.fmt(f)
}
}
+27
View File
@@ -0,0 +1,27 @@
//! Traits for record data.
use std::fmt;
use super::super::compose::ComposeBytes;
use super::super::error::{ComposeResult, ParseResult};
use super::super::flavor::Flavor;
use super::super::iana::RRType;
use super::super::parse::ParseFlavor;
/// A trait for creating record data.
pub trait RecordData<'a, F: Flavor<'a>>: fmt::Display + Sized {
/// Returns the record type for this record data instance.
fn rtype(&self) -> RRType;
/// Appends the record data to the end of a buffer.
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()>;
/// Parse the record data from a cursor 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.
fn parse<P>(rtype: RRType, parser: &mut P) -> ParseResult<Option<Self>>
where P: ParseFlavor<'a, F>;
}
+120
View File
@@ -0,0 +1,120 @@
//! DNS Records
use std::fmt;
use super::compose::ComposeBytes;
use super::error::{ComposeError, ComposeResult, ParseResult};
use super::flavor::Flavor;
use super::iana::{Class, RRType};
use super::parse::ParseFlavor;
use super::rdata::RecordData;
//------------ Record -------------------------------------------------------
#[derive(Clone, Debug)]
pub struct Record<'a, F: Flavor<'a>, D: RecordData<'a, F>> {
name: F::DName,
class: Class,
ttl: u32,
rdata: D
}
/// # Creation and Conversion
///
impl<'a, F: Flavor<'a>, D: RecordData<'a, F>> Record<'a, F, D> {
/// Creates a new record from its parts.
pub fn new(name: F::DName, class: Class, ttl: u32, rdata: D) -> Self {
Record { name: name, class: class, ttl: ttl, rdata: rdata }
}
}
/// # Element Access
///
impl<'a, F: Flavor<'a>, D: RecordData<'a, F>> Record<'a, F, D> {
/// Returns a reference to the domain name.
pub fn name(&self) -> &F::DName {
&self.name
}
/// Returns the record type.
pub fn rtype(&self) -> RRType {
self.rdata.rtype()
}
/// Returns the record class.
pub fn class(&self) -> Class {
self.class
}
/// Returns the record’s time to live.
pub fn ttl(&self) -> u32 {
self.ttl
}
/// Return a reference to the record data.
pub fn rdata(&self) -> &D {
&self.rdata
}
}
/// Parsing and Composing
///
impl<'a, F: Flavor<'a>, D: RecordData<'a, F>> Record<'a, F, D> {
pub fn parse<P>(parser: &mut P) -> ParseResult<Option<Self>>
where P: ParseFlavor<'a, F> {
let name = try!(parser.parse_name());
let rtype = try!(parser.parse_u16()).into();
let class = try!(parser.parse_u16()).into();
let ttl = try!(parser.parse_u32());
let rdlen = try!(parser.parse_u16()) as usize;
let mut rdata_sub = try!(parser.parse_sub(rdlen));
Ok(try!(D::parse(rtype, &mut rdata_sub))
.map(|rdata| Record::new(name, class, ttl, rdata)))
}
pub fn compose<C: ComposeBytes>(&self, target: &mut C)
-> ComposeResult<()> {
try!(target.push_dname_compressed(&self.name));
try!(target.push_u16(self.rdata.rtype().into()));
try!(target.push_u16(self.class.into()));
try!(target.push_u32(self.ttl));
let pos = target.pos();
try!(target.push_u16(0));
try!(self.rdata.compose(target));
let delta = target.delta(pos);
if delta > (::std::u16::MAX as usize) {
return Err(ComposeError::Overflow)
}
target.update_u16(pos, delta as u16)
}
}
//--- Display
impl<'a, F, D> fmt::Display for Record<'a, F, D>
where F: Flavor<'a>, D: RecordData<'a, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}\t{}\t{}\t{}\t{}",
self.name, self.ttl, self.class, self.rdata.rtype(),
self.rdata)
}
}
//------------ ComposeRecord ------------------------------------------------
/// Helper trait to allow composing records from tuples.
pub trait ComposeRecord {
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()>;
}
impl<'a, F, D> ComposeRecord for Record<'a, F, D>
where F: Flavor<'a>, D: RecordData<'a, F> {
fn compose<C: ComposeBytes>(&self, target: &mut C) -> ComposeResult<()> {
self.compose(target)
}
}
+94
View File
@@ -0,0 +1,94 @@
//! Dealing with bytes slices
//!
//! XXX This is an obsolete module and will be removed.
use std::mem;
use super::error::{ParseError, ParseResult};
//------------ BytesExt -----------------------------------------------------
/// A trait extending a bytes slice for reading of DNS data.
///
pub trait BytesExt {
fn split_u8(&self) -> ParseResult<(u8, &Self)>;
fn split_u16(&self) -> ParseResult<(u16, &Self)>;
fn split_u32(&self) -> ParseResult<(u32, &Self)>;
fn split_bytes(&self, at: usize) -> ParseResult<(&[u8], &Self)>;
fn tail(&self, start: usize) -> ParseResult<&Self>;
fn check_len(&self, len: usize) -> ParseResult<()>;
}
impl BytesExt for [u8] {
fn split_u8(&self) -> ParseResult<(u8, &[u8])> {
self.split_first().map(|(l,r)| (*l, r)).ok_or(ParseError::UnexpectedEnd)
}
fn split_u16(&self) -> ParseResult<(u16, &[u8])> {
try!(self.check_len(2));
let (l, r) = self.split_at(2);
let l: &[u8; 2] = unsafe { mem::transmute(l.as_ptr()) };
let l = unsafe { mem::transmute(*l) };
Ok((u16::from_be(l), r))
}
fn split_u32(&self) -> ParseResult<(u32, &[u8])> {
try!(self.check_len(4));
if self.len() < 4 { return Err(ParseError::UnexpectedEnd) }
let (l, r) = self.split_at(4);
let l: &[u8; 4] = unsafe { mem::transmute(l.as_ptr()) };
let l = unsafe { mem::transmute(*l) };
Ok((u32::from_be(l), r))
}
fn split_bytes(&self, at: usize) -> ParseResult<(&[u8], &[u8])> {
try!(self.check_len(at));
Ok(self.split_at(at))
}
fn tail(&self, start: usize) -> ParseResult<&[u8]> {
try!(self.check_len(start));
if self.len() < start { return Err(ParseError::UnexpectedEnd) }
Ok(&self[start..])
}
fn check_len(&self, len: usize) -> ParseResult<()> {
if len > self.len() { Err(ParseError::UnexpectedEnd) }
else { Ok(()) }
}
}
//------------ BytesVecExt --------------------------------------------------
/// A trait extending a bytes vec for pushing DNS data to its end.
pub trait BytesVecExt {
fn push_bytes(&mut self, data: &[u8]);
fn push_u8(&mut self, data: u8);
fn push_u16(&mut self, data: u16);
fn push_u32(&mut self, data: u32);
}
impl BytesVecExt for Vec<u8> {
fn push_bytes(&mut self, data: &[u8]) {
self.extend(data)
}
fn push_u8(&mut self, data: u8) {
let bytes: [u8; 1] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes);
}
fn push_u16(&mut self, data: u16) {
let data = data.to_be();
let bytes: [u8; 2] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes);
}
fn push_u32(&mut self, data: u32) {
let data = data.to_be();
let bytes: [u8; 4] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes);
}
}
-189
View File
@@ -1,189 +0,0 @@
//! Low-level access to wire format DNS.
//!
use std::error;
use std::fmt;
use std::mem;
use std::ptr;
use std::result;
use super::name::DomainNameSlice;
//------------ BytesBuf -----------------------------------------------------
/// A trait for writing binary DNS data.
///
pub trait BytesBuf {
type Pos: Copy;
//--- Appending basic types
fn push_bytes(&mut self, data: &[u8]);
fn push_u8(&mut self, data: u8) {
let bytes: [u8; 1] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes);
}
fn push_u16(&mut self, data: u16) {
let data = data.to_be();
let bytes: [u8; 2] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes);
}
fn push_u32(&mut self, data: u32) {
let data = data.to_be();
let bytes: [u8; 4] = unsafe { mem::transmute(data) };
self.push_bytes(&bytes);
}
//--- Updating of earlier data.
fn pos(&self) -> Self::Pos;
fn delta(&self, pos: Self::Pos) -> usize;
fn update_bytes(&mut self, pos: Self::Pos, data: &[u8]);
fn update_u8(&mut self, pos: Self::Pos, data: u8) {
let bytes: [u8; 1] = unsafe { mem::transmute(data) };
self.update_bytes(pos, &bytes);
}
fn update_u16(&mut self, pos: Self::Pos, data: u16) {
let data = data.to_be();
let bytes: [u8; 2] = unsafe { mem::transmute(data) };
self.update_bytes(pos, &bytes);
}
fn update_u32(&mut self, pos: Self::Pos, data: u32) {
let data = data.to_be();
let bytes: [u8; 4] = unsafe { mem::transmute(data) };
self.update_bytes(pos, &bytes);
}
//--- Name compression support
//
// This is disabled by default
/// Returns whether `self` can compress names.
fn can_compress(&self) -> bool { false }
/// Adds a reference to a domain name at the current position.
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<DomainNameSlice>>(&self, name: N) -> Option<u16> {
let _ = name; None
}
}
impl BytesBuf for Vec<u8> {
type Pos = usize;
fn push_bytes(&mut self, data: &[u8]) {
self.extend(data)
}
fn pos(&self) -> Self::Pos {
self.len()
}
fn delta(&self, pos: Self::Pos) -> usize {
assert!(pos < self.len());
self.len() - pos
}
fn update_bytes(&mut self, pos: Self::Pos, data: &[u8]) {
assert!(pos + data.len() < self.len());
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(),
self[pos..pos + data.len()].as_mut_ptr(),
data.len())
}
}
}
//------------ BytesSlice ---------------------------------------------------
/// A trait extending a bytes slice for reading of DNS data.
///
pub trait BytesSlice {
fn split_u8(&self) -> Result<(u8, &Self)>;
fn split_u16(&self) -> Result<(u16, &Self)>;
fn split_u32(&self) -> Result<(u32, &Self)>;
fn split_bytes(&self, at: usize) -> Result<(&[u8], &Self)>;
fn tail(&self, start: usize) -> Result<&Self>;
fn check_len(&self, len: usize) -> Result<()>;
}
impl BytesSlice for [u8] {
fn split_u8(&self) -> Result<(u8, &[u8])> {
self.split_first().map(|(l,r)| (*l, r)).ok_or(Error::PrematureEnd)
}
fn split_u16(&self) -> Result<(u16, &[u8])> {
try!(self.check_len(2));
let (l, r) = self.split_at(2);
let l: &[u8; 2] = unsafe { mem::transmute(l.as_ptr()) };
let l = unsafe { mem::transmute(*l) };
Ok((u16::from_be(l), r))
}
fn split_u32(&self) -> Result<(u32, &[u8])> {
try!(self.check_len(4));
if self.len() < 4 { return Err(Error::PrematureEnd) }
let (l, r) = self.split_at(4);
let l: &[u8; 4] = unsafe { mem::transmute(l.as_ptr()) };
let l = unsafe { mem::transmute(*l) };
Ok((u32::from_be(l), r))
}
fn split_bytes(&self, at: usize) -> Result<(&[u8], &[u8])> {
try!(self.check_len(at));
Ok(self.split_at(at))
}
fn tail(&self, start: usize) -> Result<&[u8]> {
try!(self.check_len(start));
if self.len() < start { return Err(Error::PrematureEnd) }
Ok(&self[start..])
}
fn check_len(&self, len: usize) -> Result<()> {
if len > self.len() { Err(Error::PrematureEnd) }
else { Ok(()) }
}
}
//------------ Error and Result ---------------------------------------------
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
PrematureEnd,
SizeExceeded,
Overflow,
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::PrematureEnd => "premature end of domain name",
Error::SizeExceeded => "the message size has been exceeded",
Error::Overflow => "a counter has overflowed",
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
self.description().fmt(f)
}
}
pub type Result<T> = result::Result<T, Error>;
+40 -40
View File
@@ -8,11 +8,14 @@ use std::io;
use std::net::{SocketAddr, UdpSocket};
use std::result;
use std::str::FromStr;
use domain::iana::{rrtype, Class, RRType};
use domain::message::{self, MessageBuf, MessageBuilder, RecordSection};
use domain::rdata::generic::CompactGenericRecordData;
use domain::bits::compose::ComposeVec;
use domain::bits::error::{ComposeError, FromStrError, ParseError};
use domain::bits::flavor::Lazy;
use domain::bits::iana::{Class, RRType};
use domain::bits::message::{LazyMessage, MessageBuilder, RecordIter};
use domain::bits::name::OwnedDName;
use domain::bits::rdata::generic::GenericRecordData;
use domain::resolver::conf::ResolvConf;
use domain::name::{self, DomainNameBuf};
//------------ Options ------------------------------------------------------
@@ -75,13 +78,13 @@ impl Options {
}
impl Options {
fn name(&self) -> Result<DomainNameBuf> {
fn name(&self) -> Result<OwnedDName> {
if self.name.is_empty() {
Ok(DomainNameBuf::root())
Ok(OwnedDName::root())
}
else {
let mut res = try!(DomainNameBuf::from_str(&self.name));
res.append(DomainNameBuf::root());
let mut res = try!(OwnedDName::from_str(&self.name));
res.append(OwnedDName::root());
Ok(res)
}
}
@@ -118,20 +121,20 @@ impl error::Error for Error {
}
}
impl convert::From<name::ParseError> for Error {
fn from(error: name::ParseError) -> Error {
impl convert::From<ComposeError> for Error {
fn from(error: ComposeError) -> Error {
Error { inner: Box::new(error) }
}
}
impl convert::From<rrtype::ParseError> for Error {
fn from(error: rrtype::ParseError) -> Error {
impl convert::From<FromStrError> for Error {
fn from(error: FromStrError) -> Error {
Error { inner: Box::new(error) }
}
}
impl convert::From<message::Error> for Error {
fn from(error: message::Error) -> Error {
impl convert::From<ParseError> for Error {
fn from(error: ParseError) -> Error {
Error { inner: Box::new(error) }
}
}
@@ -152,42 +155,42 @@ type Result<T> = result::Result<T, Error>;
//------------ Processing Steps ---------------------------------------------
fn create_query(options: &Options) -> Result<MessageBuf> {
let mut msg = MessageBuilder::new(::std::u16::MAX as usize, 2, true);
fn create_query(options: &Options) -> Result<Vec<u8>> {
let mut msg = try!(MessageBuilder::new(ComposeVec::new(Some(512), true)));
// XXX make a header
msg.header_mut().set_id(17);
let mut question = msg.question();
try!(question.push_question(try!(options.name()), try!(options.qtype()),
try!(options.qclass())));
try!(question.push(&(try!(options.name()), try!(options.qtype()),
try!(options.qclass()))));
// XXX set prefix
Ok(question.finish())
Ok(try!(question.finish()).finish())
}
fn send_query(options: &Options, query: &MessageBuf)
-> Result<(MessageBuf, SocketAddr)> {
fn send_query(options: &Options, query: &Vec<u8>)
-> Result<(Vec<u8>, SocketAddr)> {
send_query_udp(options, query)
}
fn send_query_udp(options: &Options, query: &MessageBuf)
-> Result<(MessageBuf, SocketAddr)> {
fn send_query_udp(options: &Options, query: &Vec<u8>)
-> Result<(Vec<u8>, SocketAddr)> {
let sock = try!(UdpSocket::bind("0.0.0.0:0"));
try!(sock.set_read_timeout(Some(options.conf().timeout)));
for server in options.conf().servers.iter() {
try!(sock.send_to(query.message_bytes(), server));
try!(sock.send_to(&query, server));
let mut buf = Vec::new();
buf.resize(2000, 0);
let (len, from) = try!(sock.recv_from(&mut buf));
buf.truncate(len);
let msg = try!(MessageBuf::from_vec(buf, 0));
return Ok((msg, from));
return Ok((buf, from));
}
Err(io::Error::new(io::ErrorKind::Other, "No more servers").into())
}
fn print_result(response: MessageBuf) {
fn print_result(response: Vec<u8>) {
let response = LazyMessage::from_bytes(&response);
println!(";; Got answer:");
println!(";; ->>HEADER<<- opcode: {}, status: {}, id: {}",
response.header().opcode(), response.header().rcode(),
@@ -216,44 +219,41 @@ fn print_result(response: MessageBuf) {
println!("");
}
let mut answer = question.answer().unwrap();
let answer = question.answer().unwrap();
if response.counts().ancount() > 0 {
println!(";; ANSWER SECTION");
print_section(&mut answer);
print_records(answer.iter());
println!("");
}
let mut authority = answer.authority().unwrap();
let authority = answer.authority().unwrap();
if response.counts().nscount() > 0 {
println!(";; AUTHORITY SECTION");
print_section(&mut authority);
print_records(authority.iter());
println!("");
}
let mut additional = authority.additional().unwrap();
let additional = authority.additional().unwrap();
if response.counts().arcount() > 0 {
println!(";; ADDITIONAL SECTION");
print_section(&mut additional);
print_records(additional.iter());
println!("");
}
}
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(), record.rdata())
fn print_records<'a>(iter: RecordIter<'a, Lazy<'a>, GenericRecordData<'a, Lazy<'a>>>) {
for record in iter {
println!("{}", record.unwrap());
}
}
//------------ Main Function ------------------------------------------------
fn main() {
let options = Options::from_args();
let query = create_query(&options).unwrap();
let (response, server) = send_query(&options, &query).unwrap();
let len = response.message_bytes().len();
let len = response.len();
print_result(response);
println!(";; Query time: not yet available.");
println!(";; SERVER: {}", server);
+4 -8
View File
@@ -1,12 +1,8 @@
/*
#[macro_use]
mod macros;
*/
pub mod bytes;
pub mod header;
pub mod iana;
pub mod message;
pub mod name;
pub mod question;
pub mod rdata;
pub mod bits;
pub mod resolver;
pub mod record;
-912
View File
@@ -1,912 +0,0 @@
//! DNS messages
//!
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::iana::{Class, RRType};
use super::name::{self, DomainName, DomainNameBuf, DomainNameSlice,
CompactDomainName};
use super::bytes::{self, BytesBuf};
use super::question::{self, Question};
use super::record::Record;
use super::rdata::traits::{RecordData, CompactRecordData};
//============ Message Slice ================================================
//------------ Message ------------------------------------------------------
#[derive(Debug)]
pub struct Message {
slice: [u8]
}
/// # Creation and Conversion
///
impl Message {
/// Creates a message from a bytes slice.
pub fn from_bytes(s: &[u8]) -> Result<&Message> {
if s.len() < mem::size_of::<FullHeader>() {
return Err(Error::OctetError(bytes::Error::PrematureEnd))
}
Ok(unsafe { mem::transmute(s) })
}
/// Creates a message from any byte slice.
unsafe fn from_bytes_unsafe(s: &[u8]) -> &Message {
mem::transmute(s)
}
/// Converts `self` into an owned message.
pub fn to_owned(&self) -> MessageBuf {
MessageBuf::from(self)
}
}
/// # Header Access
///
impl Message {
pub fn header(&self) -> &Header {
unsafe { Header::from_message(&self.slice) }
}
pub fn counts(&self) -> &HeaderCounts {
unsafe { HeaderCounts::from_message(&self.slice) }
}
pub fn question(&self) -> QuestionSection {
QuestionSection::new(self,
&self.slice[mem::size_of::<FullHeader>()..])
}
}
//------------ QuestionSection ----------------------------------------------
#[derive(Debug)]
pub struct QuestionSection<'a> {
message: &'a Message,
slice: &'a [u8],
count: u16,
}
impl<'a> QuestionSection<'a> {
fn new(message: &'a Message, slice: &'a[u8]) -> Self {
QuestionSection {
message: message,
slice: slice,
count: message.counts().qdcount(),
}
}
pub fn iter(&mut self) -> &mut Self {
self
}
pub fn answer<D: CompactRecordData<'a>>(self)
-> Option<AnswerSection<'a, D>> {
if self.count == 0 {
Some(AnswerSection::new(self.message, self.slice))
}
else { None }
}
}
impl<'a> Iterator for QuestionSection<'a> {
type Item = Result<Question<CompactDomainName<'a>>>;
fn next(&mut self) -> Option<Self::Item> {
if self.count == 0 { return None }
match Question::split_from(self.slice, &self.message.slice) {
Ok((res, slice)) => {
self.count -= 1;
self.slice = slice;
Some(Ok(res))
}
Err(e) => Some(Err(Error::from(e)))
}
}
}
//------------ RecordSection ------------------------------------------------
#[derive(Debug)]
pub struct RecordSection<'a, D: CompactRecordData<'a>> {
message: &'a Message,
slice: &'a [u8],
count: u16,
phantom: PhantomData<D>,
}
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,
phantom: PhantomData }
}
pub fn iter(&mut self) -> &mut Self {
self
}
}
impl<'a, D: CompactRecordData<'a>> Iterator for RecordSection<'a, D> {
type Item = Result<Record<CompactDomainName<'a>, D>>;
fn next(&mut self) -> Option<Self::Item> {
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)))
}
}
}
}
//------------ AnswerSection ------------------------------------------------
#[derive(Debug)]
pub struct AnswerSection<'a, D: CompactRecordData<'a>> {
inner: RecordSection<'a, D>,
}
impl<'a, D: CompactRecordData<'a>> AnswerSection<'a, D> {
fn new(message: &'a Message, slice: &'a[u8]) -> Self {
AnswerSection {
inner: RecordSection::new(message, slice,
message.counts().ancount())
}
}
pub fn authority(self) -> Option<AuthoritySection<'a, D>> {
if self.inner.count == 0 {
Some(AuthoritySection::new(self.inner.message, self.inner.slice))
}
else { None }
}
}
impl<'a, D: CompactRecordData<'a>> Deref for AnswerSection<'a, D> {
type Target = RecordSection<'a, D>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, D: CompactRecordData<'a>> DerefMut for AnswerSection<'a, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
//------------ AuthoritySection ---------------------------------------------
#[derive(Debug)]
pub struct AuthoritySection<'a, D: CompactRecordData<'a>> {
inner: RecordSection<'a, D>
}
impl<'a, D: CompactRecordData<'a>> AuthoritySection<'a, D> {
fn new(message: &'a Message, slice: &'a[u8]) -> Self {
AuthoritySection {
inner: RecordSection::new(message, slice,
message.counts().nscount())
}
}
pub fn additional(self) -> Option<AdditionalSection<'a, D>> {
if self.inner.count == 0 {
Some(AdditionalSection::new(self.inner.message,
self.inner.slice))
}
else { None }
}
}
impl<'a, D: CompactRecordData<'a>> Deref for AuthoritySection<'a, D> {
type Target = RecordSection<'a, D>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, D: CompactRecordData<'a>> DerefMut for AuthoritySection<'a, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
//------------ AdditionalSection --------------------------------------------
#[derive(Debug)]
pub struct AdditionalSection<'a, D: CompactRecordData<'a>> {
inner: RecordSection<'a, D>
}
impl<'a, D: CompactRecordData<'a>> AdditionalSection<'a, D> {
fn new(message: &'a Message, slice: &'a[u8]) -> Self {
AdditionalSection {
inner: RecordSection::new(message, slice,
message.counts().arcount())
}
}
}
impl<'a, D: CompactRecordData<'a>> Deref for AdditionalSection<'a, D> {
type Target = RecordSection<'a, D>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a, D: CompactRecordData<'a>> DerefMut for AdditionalSection<'a, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
//============ Owned Message ================================================
#[derive(Debug)]
pub struct MessageBuf {
buf: Vec<u8>,
offset: usize,
}
impl MessageBuf {
/// Creates an owned message from a bytes slice.
///
/// This is only safe if this really is a proper message.
unsafe fn from_bytes(s: &[u8], offset: usize) -> MessageBuf {
MessageBuf { buf: Vec::from(s), offset: offset }
}
pub fn from_vec(buf: Vec<u8>, offset: usize) -> Result<MessageBuf> {
if buf.len() < mem::size_of::<FullHeader>() + offset {
return Err(Error::OctetError(bytes::Error::PrematureEnd))
}
Ok(MessageBuf { buf: buf, offset: offset })
}
/// Coerces to a message slice.
pub fn as_slice(&self) -> &Message {
self
}
pub fn prefix(&self) -> &[u8] {
&self.buf[..self.offset]
}
pub fn prefix_mut(&mut self) -> &mut [u8] {
&mut self.buf[..self.offset]
}
pub fn message_bytes(&self) -> &[u8] {
&self.buf[self.offset..]
}
pub fn message_bytes_mut(&mut self) -> &mut [u8] {
&mut self.buf[self.offset..]
}
}
impl<'a> From<&'a Message> for MessageBuf {
fn from(msg: &'a Message) -> MessageBuf {
unsafe { MessageBuf::from_bytes(&msg.slice, 0) }
}
}
impl From<MessageVec> for MessageBuf {
fn from(vec: MessageVec) -> MessageBuf {
MessageBuf { buf: vec.vec, offset: vec.offset }
}
}
impl Deref for MessageBuf {
type Target = Message;
fn deref(&self) -> &Self::Target {
unsafe { Message::from_bytes_unsafe(&self.message_bytes()) }
}
}
impl AsRef<Message> for MessageBuf {
fn as_ref(&self) -> &Message { self }
}
//============ Message Builder ==============================================
//------------ MessageBuilder -----------------------------------------------
#[derive(Debug)]
pub struct MessageBuilder {
buf: MessageVec
}
impl MessageBuilder {
/// Creates a new messsage builder.
///
pub fn new(maxlen: usize, offset: usize, compress: bool)
-> MessageBuilder {
MessageBuilder { buf: MessageVec::new(maxlen, offset, compress) }
}
/// Proceeds to building the question section.
pub fn question(self) -> QuestionBuilder {
QuestionBuilder::new(self.buf)
}
/// Finish off the message and return the underlying vector.
pub fn finish(self) -> Vec<u8> {
self.buf.vec
}
}
impl Deref for MessageBuilder {
type Target = HeaderBuilder;
fn deref(&self) -> &HeaderBuilder {
HeaderBuilder::from_buf(&self.buf)
}
}
impl DerefMut for MessageBuilder {
fn deref_mut(&mut self) -> &mut HeaderBuilder {
HeaderBuilder::from_buf_mut(&mut self.buf)
}
}
//------------ QuestionBuilder ----------------------------------------------
#[derive(Debug)]
pub struct QuestionBuilder {
buf: MessageVec
}
impl QuestionBuilder {
fn new(buf: MessageVec) -> Self {
QuestionBuilder { buf: buf }
}
/// Appends a new question to the question section.
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: DomainName>(&mut self, name: N, qtype: RRType,
qclass: Class) -> Result<()> {
self.push(&Question::new(name, qtype, qclass))
}
/// Move on to the answer section
pub fn answer(self) -> AnswerBuilder {
AnswerBuilder::new(self.buf)
}
/// Finish off the message and return the underlying vector.
pub fn finish(self) -> MessageBuf {
self.buf.into()
}
}
impl Deref for QuestionBuilder {
type Target = HeaderBuilder;
fn deref(&self) -> &HeaderBuilder {
HeaderBuilder::from_buf(&self.buf)
}
}
impl DerefMut for QuestionBuilder {
fn deref_mut(&mut self) -> &mut HeaderBuilder {
HeaderBuilder::from_buf_mut(&mut self.buf)
}
}
//------------ AnswerBuilder ------------------------------------------------
pub struct AnswerBuilder {
buf: MessageVec,
}
impl AnswerBuilder {
fn new(buf: MessageVec) -> Self {
AnswerBuilder { buf: buf }
}
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 message.
pub fn finish(self) -> MessageBuf {
self.buf.into()
}
}
impl Deref for AnswerBuilder {
type Target = HeaderBuilder;
fn deref(&self) -> &HeaderBuilder {
HeaderBuilder::from_buf(&self.buf)
}
}
impl DerefMut for AnswerBuilder {
fn deref_mut(&mut self) -> &mut HeaderBuilder {
HeaderBuilder::from_buf_mut(&mut self.buf)
}
}
//------------ AuthorityBuilder ---------------------------------------------
pub struct AuthorityBuilder {
buf: MessageVec
}
impl AuthorityBuilder {
fn new(buf: MessageVec) -> Self {
AuthorityBuilder { buf: buf }
}
/*
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)
}
/// Finish off the message and return the underlying vector.
pub fn finish(self) -> MessageBuf {
self.buf.into()
}
}
impl Deref for AuthorityBuilder {
type Target = HeaderBuilder;
fn deref(&self) -> &HeaderBuilder {
HeaderBuilder::from_buf(&self.buf)
}
}
impl DerefMut for AuthorityBuilder {
fn deref_mut(&mut self) -> &mut HeaderBuilder {
HeaderBuilder::from_buf_mut(&mut self.buf)
}
}
//------------ AdditionalBuilder --------------------------------------------
pub struct AdditionalBuilder {
buf: MessageVec
}
impl AdditionalBuilder {
fn new(buf: MessageVec) -> Self {
AdditionalBuilder { buf: buf }
}
/*
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 {
self.buf.into()
}
}
impl Deref for AdditionalBuilder {
type Target = HeaderBuilder;
fn deref(&self) -> &HeaderBuilder {
HeaderBuilder::from_buf(&self.buf)
}
}
impl DerefMut for AdditionalBuilder {
fn deref_mut(&mut self) -> &mut HeaderBuilder {
HeaderBuilder::from_buf_mut(&mut self.buf)
}
}
//------------ HeaderBuilder ------------------------------------------------
#[derive(Debug)]
pub struct HeaderBuilder {
buf: MessageVec
}
impl HeaderBuilder {
fn from_buf(buf: &MessageVec) -> &HeaderBuilder {
unsafe { mem::transmute(buf) }
}
fn from_buf_mut(buf: &mut MessageVec) -> &mut HeaderBuilder {
unsafe { mem::transmute(buf) }
}
}
impl HeaderBuilder {
/// Returns a reference to the message header.
pub fn header(&self) -> &Header {
self.buf.header()
}
/// Returns a mutable reference to the message header.
pub fn header_mut(&mut self) -> &mut Header {
self.buf.header_mut()
}
/// Returns a reference to the message header counts.
pub fn counts(&self) -> &HeaderCounts {
self.buf.counts()
}
/// Returns a reference to the prefix.
pub fn prefix(&self) -> &[u8] {
self.buf.prefix()
}
/// Returns a mutable reference to the prefix.
pub fn prefix_mut(&mut self) -> &mut [u8] {
self.buf.prefix_mut()
}
/// Returns a reference to the message so far.
pub fn message(&self) -> &Message {
unsafe { Message::from_bytes_unsafe(self.buf.message_bytes()) }
}
/// Returns the lenth of the message so far.
pub fn len(&self) -> usize {
self.buf.message_bytes().len()
}
}
//------------ MessageVec ---------------------------------------------------
/// A bytes vector for assembling DNS messages.
///
/// This private type does all the heavy lifting for creating a message.
///
#[derive(Debug)]
struct MessageVec {
/// The underlying vector.
vec: Vec<u8>,
/// When writing to a stream socket, the message actually starts with
/// a two byte length indicator. In order to be able to assemble such
/// messages herein, we generalize this a little and allow an
/// arbitrarily sized prefix. This field keeps the offset where the
/// actual message starts.
offset: usize,
/// Maximum size of the message.
///
/// While existing wire protocols limit messages to 65535 bytes, we
/// can build messages up to `std::usize::MAX` bytes in length.
maxlen: usize,
/// Whether then message has exceeded its length and has been truncated.
///
/// We need to store this separatly since cutting back to the checkpoint
/// will get us below the maximum length again.
truncated: bool,
/// Position of the optional check point.
///
/// If this is set, the vector will be cut back to this length when
/// it crosses its length boundary.
checkpoint: Option<usize>,
/// If we do compression, we will store domain names and their offset
/// in this here map. If we don't do compression, there is no map.
compress: Option<HashMap<DomainNameBuf, u16>>,
}
impl MessageVec {
fn new(maxlen: usize, offset: usize, compress: bool) -> MessageVec {
MessageVec {
vec: vec![0; offset + mem::size_of::<FullHeader>()],
offset: offset,
maxlen: maxlen,
truncated: false,
checkpoint: None,
compress: if compress { Some(HashMap::new()) }
else { None }
}
}
fn prefix(&self) -> &[u8] {
&self.vec[..self.offset]
}
fn prefix_mut(&mut self) -> &mut [u8] {
&mut self.vec[..self.offset]
}
fn message_bytes(&self) -> &[u8] {
&self.vec[self.offset..]
}
fn message_bytes_mut(&mut self) -> &mut [u8] {
&mut self.vec[self.offset..]
}
fn header(&self) -> &Header {
unsafe { Header::from_message(self.message_bytes()) }
}
fn header_mut(&mut self) -> &mut Header {
unsafe { Header::from_message_mut(self.message_bytes_mut()) }
}
fn counts(&self) -> &HeaderCounts {
unsafe { HeaderCounts::from_message(self.message_bytes()) }
}
fn counts_mut(&mut self) -> &mut HeaderCounts {
unsafe { HeaderCounts::from_message_mut(self.message_bytes_mut()) }
}
fn keep_pushing(&mut self, len: usize) -> bool {
if self.truncated { false }
else if self.vec.len() + len > self.maxlen {
self.checkpoint.map(|len| self.vec.truncate(len));
self.truncated = true;
self.header_mut().set_tc(true);
false
}
else { true }
}
fn checkpoint(&mut self) {
self.checkpoint = Some(self.vec.len())
}
fn rollback(&mut self) {
if let Some(len) = self.checkpoint {
self.vec.truncate(len);
self.checkpoint = None;
}
}
fn push<B, I>(&mut self, buildop: B, incop: I) -> Result<()>
where B: FnOnce(&mut MessageVec) -> Result<()>,
I: FnOnce(&mut HeaderCounts) -> bytes::Result<()> {
self.checkpoint();
try!(buildop(self));
if self.truncated {
self.rollback();
Err(bytes::Error::SizeExceeded.into())
}
else {
incop(self.counts_mut()).map_err(|err| {
self.rollback();
err.into()
})
}
}
/*
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)
}
*/
}
impl BytesBuf for MessageVec {
type Pos = <Vec<u8> as BytesBuf>::Pos;
fn push_bytes(&mut self, data: &[u8]) {
if self.keep_pushing(data.len()) {
self.vec.push_bytes(data)
}
}
fn pos(&self) -> Self::Pos { self.vec.pos() }
fn delta(&self, pos: Self::Pos) -> usize { self.vec.delta(pos) }
fn update_bytes(&mut self, pos: Self::Pos, data: &[u8]) {
self.vec.update_bytes(pos, data)
}
fn can_compress(&self) -> bool {
self.compress.is_some()
}
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 }
let name = name.as_ref().to_owned();
map.insert(name, (self.vec.len() - self.offset) as 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
}
}
}
//============ Error and Result =============================================
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
NameError(name::ErrorKind),
OctetError(bytes::Error),
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::NameError(ref kind) => kind.description(),
Error::OctetError(ref error) => {
use std::error::Error;
error.description()
}
}
}
}
impl convert::From<bytes::Error> for Error {
fn from(error: bytes::Error) -> Error {
Error::OctetError(error)
}
}
impl convert::From<name::Error> for Error {
fn from(error: name::Error) -> Error {
match error {
name::Error::NameError(kind) => Error::NameError(kind),
name::Error::OctetError(error) => Error::OctetError(error),
}
}
}
impl convert::From<question::Error> for Error {
fn from(error: question::Error) -> Error {
match error {
question::Error::NameError(kind) => Error::NameError(kind),
question::Error::OctetError(kind) => Error::OctetError(kind),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
self.description().fmt(f)
}
}
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();
}
}
-131
View File
@@ -1,131 +0,0 @@
//! A single question from a DNS message
//!
use std::convert;
use std::error;
use std::fmt;
use std::result;
use super::iana::{Class, RRType};
use super::name::{self, DomainName, DomainNameBuf, DomainNameSlice,
CompactDomainName};
use super::bytes::{self, BytesSlice, BytesBuf};
//------------ Question -----------------------------------------------------
#[derive(Debug)]
pub struct Question<N: DomainName> {
qname: N,
qtype: RRType,
qclass: Class,
}
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 }
}
/// Returns the requested domain name.
pub fn qname(&self) -> &N {
&self.qname
}
/// Returns the requested record type.
pub fn qtype(&self) -> RRType {
self.qtype
}
/// Returns the requested class.
pub fn qclass(&self) -> Class {
self.qclass
}
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(())
}
}
//--- Addtional functions and methods for owned questions
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 ---------------------------------------------
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
NameError(name::ErrorKind),
OctetError(bytes::Error),
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::NameError(ref kind) => kind.description(),
Error::OctetError(ref error) => {
use std::error::Error;
error.description()
}
}
}
}
impl convert::From<bytes::Error> for Error {
fn from(error: bytes::Error) -> Error {
Error::OctetError(error)
}
}
impl convert::From<name::Error> for Error {
fn from(error: name::Error) -> Error {
match error {
name::Error::NameError(kind) => Error::NameError(kind),
name::Error::OctetError(error) => Error::OctetError(error),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use std::error::Error;
self.description().fmt(f)
}
}
pub type Result<T> = result::Result<T, Error>;
-92
View File
@@ -1,92 +0,0 @@
//! Generic Record Data Types
use std::fmt;
use super::super::bytes::BytesBuf;
use super::super::iana::RRType;
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::<CompactNS<'a>>(f),
_ => "...".fmt(f)
}
}
}
-94
View File
@@ -1,94 +0,0 @@
use std::fmt;
use std::net;
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 {
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() -> RRType { RRType::A }
fn push_buf<B: BytesBuf>(&self, buf: &mut B) -> Result<()> {
for i in self.addr.octets().iter() {
buf.push_u8(*i);
}
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());
let (c, rdata) = try!(rdata.split_u8());
let (d, _) = try!(rdata.split_u8());
Ok(A::new(net::Ipv4Addr::new(a, b, c, d)))
}
}
impl fmt::Display for A {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.addr.fmt(f)
}
}
//------------ NS -----------------------------------------------------------
#[derive(Debug)]
pub struct NS<N: DomainName> {
nsdname: N
}
pub type CompactNS<'a> = NS<CompactDomainName<'a>>;
impl<N: DomainName> NS<N> {
pub fn new(nsdname: N) -> Self {
NS { nsdname: nsdname }
}
pub fn nsdname(&self) -> &N {
&self.nsdname
}
}
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_compressed(buf));
Ok(())
}
}
impl<'a> CompactConcreteRecordData<'a> for NS<CompactDomainName<'a>> {
fn parse(rdata: &'a[u8], context: &'a [u8]) -> Result<Self> {
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)
}
}
-89
View File
@@ -1,89 +0,0 @@
//! 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.
use std::fmt;
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: fmt::Display {
/// 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<()>;
}
/// 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>: fmt::Display + Sized {
/// 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<()>;
}
/// 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: 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)))) }
}
}
-94
View File
@@ -1,94 +0,0 @@
use std::fmt;
use super::name::{DomainName, CompactDomainName};
use super::bytes::{self, BytesSlice, BytesBuf};
use super::question::Result; // XXX Temporary.
use super::iana::{Class, RRType};
use super::rdata::traits::{RecordData, CompactRecordData};
//------------ Record -------------------------------------------------------
#[derive(Debug)]
pub struct Record<N: DomainName, D: RecordData> {
name: N,
rclass: Class,
ttl: u32,
rdata: D
}
//--- 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 push_buf<B: BytesBuf>(&self, buf: &mut B) -> Result<()> {
try!(self.name.push_buf(buf));
self.rdata.rtype().push_buf(buf);
self.rclass.push_buf(buf);
buf.push_u32(self.ttl);
let pos = buf.pos();
buf.push_u16(0);
try!(self.rdata.push_buf(buf));
let delta = buf.delta(pos);
if delta > (::std::u16::MAX as usize) {
return Err(bytes::Error::Overflow.into())
}
buf.update_u16(pos, delta as u16);
Ok(())
}
/// Returns the domain name.
pub fn name(&self) -> &N { &self.name }
/// Returns the record type.
pub fn rtype(&self) -> RRType { self.rdata.rtype() }
/// Returns the record class.
pub fn rclass(&self) -> Class { self.rclass }
/// Returns the record’s time to live.
pub fn ttl(&self) -> u32 { self.ttl }
/// Returns the raw record data.
pub fn rdata(&self) -> &D { &self.rdata }
}
//---- 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))
}
}
}
}
//---- Traits
impl <N: DomainName, D: RecordData> fmt::Display for Record<N, D> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}\t{}\t{}\t{}\t{}",
self.name, self.ttl, self.rclass, self.rdata.rtype(),
self.rdata)
}
}
+8 -7
View File
@@ -19,7 +19,8 @@ use std::path::Path;
use std::str::{self, FromStr, SplitWhitespace};
use std::result;
use std::time::Duration;
use ::name::{self, DomainNameBuf};
use ::bits::error::FromStrError;
use ::bits::name::OwnedDName;
//------------ ResolvOptions ------------------------------------------------
@@ -119,7 +120,7 @@ pub struct ResolvConf {
pub servers: Vec<SocketAddr>,
/// Search list for host-name lookup.
pub search: Vec<DomainNameBuf>,
pub search: Vec<OwnedDName>,
/// TODO Sortlist
/// sortlist: ??
@@ -171,7 +172,7 @@ impl ResolvConf {
self.servers.push(SocketAddr::new(addr, 53));
}
if self.search.is_empty() {
self.search.push(DomainNameBuf::root())
self.search.push(OwnedDName::root())
}
}
}
@@ -226,7 +227,7 @@ impl ResolvConf {
}
fn parse_domain(&mut self, mut words: SplitWhitespace) -> Result<()> {
let domain = try!(DomainNameBuf::from_str(try!(next_word(&mut words))));
let domain = try!(OwnedDName::from_str(try!(next_word(&mut words))));
self.search = Vec::new();
self.search.push(domain);
no_more_words(words)
@@ -235,7 +236,7 @@ impl ResolvConf {
fn parse_search(&mut self, words: SplitWhitespace) -> Result<()> {
let mut search = Vec::new();
for word in words {
search.push(try!(DomainNameBuf::from_str(word)))
search.push(try!(OwnedDName::from_str(word)))
}
self.search = search;
Ok(())
@@ -352,8 +353,8 @@ impl convert::From<io::Error> for Error {
}
}
impl convert::From<name::ParseError> for Error {
fn from(_: name::ParseError) -> Error {
impl convert::From<FromStrError> for Error {
fn from(_: FromStrError) -> Error {
Error::ParseError
}
}