Bring back dig.

This commit is contained in:
Martin Hoffmann
2017-12-21 08:55:12 +01:00
parent f0f138fc94
commit 2e56c7adff
16 changed files with 662 additions and 279 deletions
-1
View File
@@ -23,7 +23,6 @@ futures = "0.1.14"
tokio = { git = "https://github.com/tokio-rs/tokio.git", branch="new-crate" }
[dev-dependencies]
argparse = "0.2"
native-tls = "0.1.2"
tokio-io = "0.1.2"
tokio-tls = "0.1.2"
+153 -125
View File
@@ -1,15 +1,18 @@
/*
extern crate argparse;
extern crate bytes;
extern crate domain;
extern crate tokio_core;
extern crate failure;
use std::error;
use std::result;
use std::{env, io};
use std::net::{SocketAddr, UdpSocket};
use std::process::exit;
use std::str::FromStr;
use domain::bits::message::{MessageBuf, RecordSection};
use domain::bits::name::{DNameBuf, DNameSlice};
use std::time::Instant;
use bytes::BytesMut;
use failure::Error;
use domain::bits::{Dname, Message, MessageBuilder, ParsedDname, RecordSection};
use domain::iana::{Class, Rtype};
use domain::resolv::{ResolvConf, Resolver};
use domain::rdata::AllRecordData;
use domain::resolv::ResolvConf;
//------------ Options ------------------------------------------------------
@@ -28,9 +31,9 @@ struct Options {
// -y [hmac:name:key]
// -4
// -6
name: String, // name
qtype: String, // type Type as string
qclass: String, // class
name: Dname,
qtype: Rtype,
qclass: Class,
// queryopt...
conf: ResolvConf,
@@ -43,151 +46,176 @@ impl Options {
conf.finalize();
conf.options.use_vc = true;
Options {
name: String::new(),
qtype: String::new(), // default depends on name.
qclass: "IN".to_string(),
name: Dname::root(),
qtype: Rtype::A,
qclass: Class::In,
conf: conf,
}
}
fn from_args() -> Options {
fn from_args() -> Result<Options, Error> {
let mut res = Options::new();
res.parse();
res
res.parse()?;
Ok(res)
}
fn parse(&mut self) {
use argparse::{ArgumentParser, Store};
fn parse(&mut self) -> Result<(), Error> {
let mut args = env::args();
args.next();
let mut parser = ArgumentParser::new();
parser.refer(&mut self.name)
.add_argument("name", Store, "name of the resource record");
parser.refer(&mut self.qtype)
.add_argument("type", Store, "query type");
parser.refer(&mut self.qclass)
.add_argument("class", Store, "query class");
parser.parse_args_or_exit();
match args.next() {
Some(name) => self.name = Dname::from_str(&name)?,
None => {
println!("Usage: dig qname [qtype [qclass]]");
exit(1);
}
};
match args.next() {
Some(qtype) => self.qtype = Rtype::from_str(&qtype)?,
None => return Ok(()),
}
if let Some(qclass) = args.next() {
self.qclass = Class::from_str(&qclass)?
}
Ok(())
}
}
impl Options {
fn name(&self) -> Result<DNameBuf> {
if self.name.is_empty() {
Ok(DNameSlice::root().to_owned())
}
else {
let mut res = try!(DNameBuf::from_str(&self.name));
res.append_root().unwrap();
Ok(res)
}
}
fn qtype(&self) -> Result<Rtype> {
if self.qtype.is_empty() {
Ok(if self.name.is_empty() { Rtype::Ns } else { Rtype::A })
}
else {
Ok(try!(Rtype::from_str(&self.qtype)))
}
}
fn qclass(&self) -> Result<Class> {
Ok(Class::In)
}
fn conf(&self) -> &ResolvConf { &self.conf }
}
//------------ Error and Result ---------------------------------------------
impl Options {
fn create_request(&self) -> Result<Message, Error> {
let mut msg = MessageBuilder::new_udp();
msg.header_mut().set_rd(true);
msg.push((&self.name, self.qtype, self.qclass))?;
let mut msg = msg.opt()?;
msg.set_udp_payload_size(4096);
Ok(Message::from_bytes(msg.freeze())?)
}
type Error = Box<error::Error>;
type Result<T> = result::Result<T, Error>;
//------------ Processing Steps ---------------------------------------------
fn query(options: Options) -> MessageBuf {
Resolver::run_with_conf(options.conf().clone(), |resolv| {
resolv.query((options.name().unwrap(), options.qtype().unwrap(),
options.qclass().unwrap()))
}).unwrap()
}
fn print_result(response: MessageBuf) {
println!(";; Got answer:");
println!(";; ->>HEADER<<- opcode: {}, status: {}, id: {}",
response.header().opcode(), response.header().rcode(),
response.header().id());
print!(";; flags:");
if response.header().qr() { print!(" qr"); }
if response.header().aa() { print!(" aa"); }
if response.header().tc() { print!(" tc"); }
if response.header().rd() { print!(" rd"); }
if response.header().ra() { print!(" ra"); }
if response.header().ad() { print!(" ad"); }
if response.header().cd() { print!(" cd"); }
println!("; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}",
response.counts().qdcount(), response.counts().ancount(),
response.counts().nscount(), response.counts().arcount());
println!("");
let mut question = response.question();
if response.counts().qdcount() > 0 {
println!(";; QUESTION SECTION");
for item in &mut question {
let item = item.unwrap();
println!("; {}\t\t{}\t{}", item.qname(),
item.qclass(), item.qtype());
fn query(&self, request: Message) -> Result<Message, Error> {
for server in &self.conf.servers {
if let Some(res) = self.query_udp(&request, server.addr)? {
return Ok(res)
}
}
println!("");
Err(io::Error::new(io::ErrorKind::TimedOut,
"no servers could be reached").into())
}
let mut answer = question.answer().unwrap();
if response.counts().ancount() > 0 {
println!(";; ANSWER SECTION");
print_records(&mut answer);
println!("");
fn query_udp(&self, request: &Message, addr: SocketAddr)
-> Result<Option<Message>, Error> {
let sock = UdpSocket::bind("0.0.0.0:0")?;
sock.send_to(request.as_slice(), addr)?;
let done = Instant::now() + self.conf.timeout;
while Instant::now() < done {
sock.set_read_timeout(Some(done - Instant::now()))?;
let mut buf = BytesMut::with_capacity(4096);
unsafe { buf.set_len(4096) };
let (size, raddr) = match sock.recv_from(buf.as_mut()) {
Ok(res) => res,
Err(err) => {
if err.kind() == io::ErrorKind::TimedOut {
return Ok(None)
}
else {
return Err(err.into())
}
}
};
if raddr != addr {
// XXX This may actually be wrong ...
continue
}
unsafe { buf.set_len(size) };
if let Ok(res) = Message::from_bytes(buf.freeze()) {
if res.is_answer(request) {
return Ok(Some(res))
}
}
}
Ok(None)
}
let mut authority = answer.next_section().unwrap().unwrap();
if response.counts().nscount() > 0 {
println!(";; AUTHORITY SECTION");
print_records(&mut authority);
fn print_result(&self, response: Message) -> Result<(), Error> {
println!(";; Got answer:");
println!(";; ->>HEADER<<- opcode: {}, status: {}, id: {}",
response.header().opcode(), response.header().rcode(),
response.header().id());
print!(";; flags:");
if response.header().qr() { print!(" qr"); }
if response.header().aa() { print!(" aa"); }
if response.header().tc() { print!(" tc"); }
if response.header().rd() { print!(" rd"); }
if response.header().ra() { print!(" ra"); }
if response.header().ad() { print!(" ad"); }
if response.header().cd() { print!(" cd"); }
println!("; QUERY: {}, ANSWER: {}, AUTHORITY: {}, ADDITIONAL: {}",
response.header_counts().qdcount(),
response.header_counts().ancount(),
response.header_counts().nscount(),
response.header_counts().arcount());
println!("");
let mut question = response.question();
if response.header_counts().qdcount() > 0 {
println!(";; QUESTION SECTION");
for item in &mut question {
let item = item.unwrap();
println!("; {}", item);
}
println!("");
}
let mut answer = question.answer().unwrap();
if response.header_counts().ancount() > 0 {
println!(";; ANSWER SECTION");
self.print_records(&mut answer);
println!("");
}
let mut authority = answer.next_section().unwrap().unwrap();
if response.header_counts().nscount() > 0 {
println!(";; AUTHORITY SECTION");
self.print_records(&mut authority);
println!("");
}
let mut additional = authority.next_section().unwrap().unwrap();
if response.header_counts().arcount() > 0 {
println!(";; ADDITIONAL SECTION");
self.print_records(&mut additional);
println!("");
}
Ok(())
}
let mut additional = authority.next_section().unwrap().unwrap();
if response.counts().arcount() > 0 {
println!(";; ADDITIONAL SECTION");
print_records(&mut additional);
println!("");
fn print_records(&self, section: &mut RecordSection) {
for record in section {
let record = record.unwrap()
.into_record::<AllRecordData<ParsedDname>>()
.unwrap().unwrap();
println!("{}", record);
}
}
}
fn print_records(section: &mut RecordSection) {
for record in section {
println!("{}", record.unwrap());
fn run() -> Result<(), Error> {
let options = Self::from_args()?;
let request = options.create_request()?;
let response = options.query(request)?;
options.print_result(response)
}
}
//------------ Main Function ------------------------------------------------
*/
fn main() {
/*
let options = Options::from_args();
let response = query(options);
let len = response.len();
print_result(response);
println!(";; Query time: not yet available.");
println!(";; SERVER: we don't currently know.");
println!(";; WHEN: not yet available.");
println!(";; MSG SIZE rcvd: {} bytes", len);
println!("");
*/
if let Err(err) = Options::run() {
println!("{}", err);
exit(1);
}
}
+6
View File
@@ -199,6 +199,12 @@ pub trait Compress {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf>;
}
impl<'a, C: Compress + 'a> Compress for &'a C {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
(*self).compress(buf)
}
}
//------------ Compressor ----------------------------------------------------
+2
View File
@@ -415,6 +415,7 @@ impl QuestionSection {
///
/// [`RecordSection`]: struct.RecordSection.html
pub fn answer(mut self) -> Result<RecordSection, ParsedDnameError> {
// XXX Use Parser::skip here.
for question in &mut self {
let _ = question?;
}
@@ -576,6 +577,7 @@ impl RecordSection {
Some(section) => section,
None => return Ok(None)
};
// XXX Use Parser::skip here.
for record in &mut self {
let _ = try!(record);
}
+348 -72
View File
@@ -4,75 +4,125 @@
//! contain, among other things, the number of entries in the following four
//! section which then contain these entries without any further
//! delimitation. In order to safely build a correct message, it thus needs
//! to be assembled step by step, entry by entry. This module provides four
//! types, each responsible for assembling one of the entry sections.
//! to be assembled step by step, entry by entry. This module provides a
//! number of types that can be used to assembling entries in these sections.
//!
//! You start out with a [`MessageBuilder`] which you can either create from
//! an existing [`Composer`] or, as a shortcut, either completely [`new()`]
//! or from an existing bytes vector via [`from_vec()`]. Like all of these
//! type, the [`MessageBuilder`] allows access to the header section. In
//! Message building happens by appending data to a [`BytesMut`] buffer. This
//! buffer is automatically grown to accomodate the data if necessary. It
//! does, however, consider the size limit that all DNS messages have. Thus,
//! when you start building by creating a [`MessageBuilder`], you can pass
//! an initial buffer size, a size limit, and a strategy for growing to its
//! [`with_params`] function. Alternatively, you can create the message atop
//! an existing buffer via [`from_buf`]. In this case you can adjust the
//! limits via methods such as [`set_limit`].
//!
//! All types allow to change the limit later. This is useful if you know
//! already that your message will have to end with an OPT or TSIG record.
//! Since for these you also know the size in advance, you can reserve space
//! by setting a lower limit and increase it only when finally adding those
//! records.
//!
//! Because domain name compression is somewhat expensive, it needs to be
//! enable explicitely through the [`enable_compression`] method.
//!
//! The inital [`MessageBuilder`] allows access to the two first sections of
//! the new message. The
//! header section can be accessed via [`header`] and [`header_mut`]. In
//! addition, it is used for building the *question section* of the message.
//! This section contains [`Question`]s to be asked of a name server,
//! normally exactly one. You can add questions using the
//! [`push()`](struct.MessageBuilder.html#method.push) method.
//! [`push`] method.
//!
//! [`BytesMut`]: ../../../bytes/struct.BytesMut.html
//! [`with_params`]: struct.MessageBuilder.html#method.with_params
//! [`from_buf`]: struct.MessageBuilder.html#method.from_buf
//! [`enable_compression`]: struct.MessageBuilder.html#method.enable_compression
//! [`header`]: struct.MessageBuilder.html#method.header
//! [`header_mut`]: struct.MessageBuilder.html#method.header_mut
//! [`push`]: struct.MessageBuilder.html#method.push
//! [`set_limit`]: struct.MessageBuilder.html#method.set_limit
//!
//! Once you are happy with the question section, you can proceed to the
//! next section, the *answer section,* by calling the
//! [`answer()`](struct.MessageBuilder.html#method.answer) method. In a
//! response, this section contains those resource records that answer the
//! question. The section is represented by the [`AnswerBuilder`] type.
//! It, too, has a [`push()`](struct.AnswerBuilder.html#method.push) method,
//! but for [`Record`]s.
//! [`answer`] method.
//! In a response, this section contains those resource records that answer
//! the question. The section is represented by the [`AnswerBuilder`] type.
//! It, too, has a [`push`] method, but for adding [`Record`]s.
//!
//! A call to [`authority()`](struct.AnswerBuilder.html#method.authority)
//! moves on to the *authority section*. It contains resource records that
//! point to the name servers that serve authoritative for the question.
//! Like with the answer section,
//! [`push()`](struct.AuthorityBuilder.html#method.push) adds records to this
//! section.
//! [`answer`]: struct.MessageBuilder.html#method.answer
//! [`push`]: struct.AnswerBuilder.html#method.push
//!
//! A call to [`authority`] moves on to the *authority section*. It contains
//! resource records that allow to identify the name servers that are
//! authoritative for the records requested in the question. As with the
//! answer section, [`push`] adds records to this section.
//!
//! [`authority`]: struct.AnswerBuilder.html#method.authority
//! [`push`]: struct.AuthorityBuilder.html#method.push
//!
//! The final section is the *additional section.* Here a name server can add
//! information it believes will help the client to get to the answer it
//! really wants. Which these are depends on the question and is generally
//! given in RFCs that define the record types. Unsurprisingly, you will
//! arrive at a [`AdditionalBuilder`] by calling the
//! [`additional()`](struct.AuthorityBuilder.html#method.additional) method
//! once you are done with the authority section.
//! arrive at an [`AdditionalBuilder`] by calling the [`additional`] method
//! once you are done with the authority section. Adding records, once again,
//! happens via the [`push`] method.
//!
//! [`additional`]: struct.AuthorityBuilder.html#method.additional
//! [`push`]: struct.AdditionalBuilder.html#method.push
//!
//! Once you are done with the additional section, too, you call
//! [`finish()`](struct.AdditionalBuilder.html#method.finish) to retrieve
//! the bytes vector with the assembled message data.
//! [`finish`] to retrieve the underlying bytes buffer or [`freeze`] to get
//! a bytes value instead.
//!
//! [`finish`]: struct.AuthorityBuilder.html#method.finish
//! [`freeze`]: struct.AuthorityBuilder.html#method.freeze
//!
//! Since at least some of the sections are empty in many messages, for
//! instance, a simple request only contains a single question, there are
//! shortcuts in place to skip over sections. Each type can go to any later
//! section through the methods named above. Each type also has a `finish()`
//! method to arrive at the final data quickly.
//! section through the methods named above. Each type also has the `finish`
//! and `freeze` methods to arrive at the final data quickly.
//!
//! There is one more type: [`OptBuilder`]. It can be used to assemble an
//! OPT record in the additional section. This is helpful because the OPT
//! record in turn is a sequence of options that need to be assembled one
//! by one.
//!
//! An [`OptBuilder`] can be retrieved from an [`AdditionalBuilder`] via its
//! [`opt`] method. Options can then be added as usually via [`push`]. Once
//! done, you can return to the additional section with [`additional`] or,
//! if your OPT record is the final record, conclude message construction
//! via [`finish`] or [`freeze`].
//!
//! [`opt`]: struct.AdditionalBuilder.html#method.opt
//! [`push`]: struct.OptBuilder.html#method.push
//! [`additional`]: struct.OptBuilder.html#method.additional
//! [`finish`]: struct.OptBuilder.html#method.finish
//! [`freeze`]: struct.OptBuilder.html#method.freeze
//!
//! # Example
//!
//! To summarize all of this, here is an example that builds a
//! response to an A query for example.com that contains two A records and
//! nothing else.
//! and empty OPT record setting the UDP payload size.
//!
//! ```
//! /*
//! use std::str::FromStr;
//! use domain::bits::{ComposeMode, DNameBuf, MessageBuilder, Question};
//! use domain::bits::{Dname, MessageBuilder};
//! use domain::iana::Rtype;
//! use domain::rdata::A;
//!
//! let name = DNameBuf::from_str("example.com.").unwrap();
//! let mut msg = MessageBuilder::new(ComposeMode::Limited(512),
//! true).unwrap();
//! let name = Dname::from_str("example.com.").unwrap();
//! let mut msg = MessageBuilder::new_udp();
//! msg.header_mut().set_rd(true);
//! msg.push((&name, Rtype::A));
//! let mut msg = msg.answer();
//! msg.push((&name, 86400, A::from_octets(192, 0, 2, 1))).unwrap();
//! msg.push((&name, 86400, A::from_octets(192, 0, 2, 2))).unwrap();
//! let _ = msg.finish(); // get the Vec<u8>
//! */
//! let mut msg = msg.opt().unwrap();
//! msg.set_udp_payload_size(4096);
//! let _ = msg.freeze(); // get the Bytes
//! ```
//!
//! [`AdditionalBuilder`]: struct.AdditionalBuilder.html
@@ -80,6 +130,7 @@
//! [`AuthorityBuilder`]: struct.AuthorityBuilder.html
//! [`Composer`]: ../compose/Composer.html
//! [`MessageBuilder`]: struct.MessageBuilder.html
//! [`OptBuilder`]: struct.OptBuilder.html
//! [`Question`]: ../question/struct.Question.html
//! [`Record`]: ../record/struct.Record.html
//! [`new()`]: struct.MessageBuilder.html#method.new
@@ -101,12 +152,22 @@ use super::record::Record;
//------------ MessageBuilder -----------------------------------------------
/// A type for building the question section of a DNS message.
/// Starts building a DNS message.
///
/// This type starts building a DNS message and allows adding questions to
/// its question section. See the [module documentation] for details.
/// its question section. See the [module documentation] for an overview of
/// how to build a message.
///
/// Message builders operate atop a [`BytesMut`] byte buffer. There are a
/// number of functions to create a builder either using an existing
/// buffer or with a newly created buffer.
///
/// Once created, it is possible to access the message header or append
/// questions to the question section before proceeding to the subsequent
/// parts of the message.
///
/// [module documentation]: index.html
/// [`BytesMut`]: ../../../bytes/struct.BytesMut.html
#[derive(Clone, Debug)]
pub struct MessageBuilder {
target: MessageTarget,
@@ -116,18 +177,66 @@ pub struct MessageBuilder {
/// # Creation and Preparation
///
impl MessageBuilder {
/// Creates a new builder for a UDP message.
///
/// The builder will use a new bytes buffer. The buffer will have a
/// capacity of 512 bytes and will also be limited to that.
///
/// This will result in a UDP message following the original limit. If you
/// want to create larger messages, you should signal this through the use
/// of EDNS.
pub fn new_udp() -> Self {
Self::with_params(512, 512, 0)
}
/// Creates a new builder for a TCP message.
///
/// The builder will use a new buffer. It will be limited to 65535 bytes,
/// starting with the capacity given and also growing by that amount.
///
/// Since DNS messages are preceded on TCP by a two octet length
/// inicator, the function will add two bytes with zero before the
/// message. Once you have completed your message, you can use can set
/// these two bytes to the size of the message. But remember that they
/// are in network byte order.
pub fn new_tcp(capacity: usize) -> Self {
let mut buf = BytesMut::with_capacity(capacity + 2);
buf.put_u16::<BigEndian>(0);
let mut res = Self::from_buf(buf);
res.set_limit(::std::u16::MAX as usize);
res.set_page_size(capacity);
res
}
/// Creates a new message builder using an existing bytes buffer.
///
/// The builders initial limit will be equal to whatever capacity is
/// left in the buffer. As a consequence, the builder will never grow
/// beyond that remaining capacity.
pub fn from_buf(buf: BytesMut) -> Self {
MessageBuilder { target: MessageTarget::from_buf(buf) }
}
/// Creates a message builder with the given capacity.
///
/// The builder will have its own newly created bytes buffer. Its inital
/// limit will be equal to the capacity of that buffer. This may be larger
/// than `capacity`. If you need finer control over the limit, use
/// [`with_params`] instead.
///
/// [`with_params`]: #method.with_params
pub fn with_capacity(capacity: usize) -> Self {
Self::from_buf(BytesMut::with_capacity(capacity))
}
/// Creates a new message builder.
///
/// A new buffer will be created for this builder. It will initially
/// allocate space for at least `initial` bytes. The message will never
/// exceed a size of `limit` bytes. Whenever the buffers capacity is
/// exhausted, the builder will allocate at least another `page_size`
/// bytes. If `page_size` is set to `0`, the builder will allocate at
/// most once and then enough bytes to have room for the limit.
pub fn with_params(initial: usize, limit: usize, page_size: usize)
-> Self {
let mut res = Self::with_capacity(initial);
@@ -136,14 +245,40 @@ impl MessageBuilder {
res
}
/// Enables support for domain name compression.
///
/// After this method is called, the domain names in questions, the owner
/// domain names of resource records, and domain names appearing in the
/// record data of record types defined in [RFC 1035] will be compressed.
///
/// [RFC 1035]: ../../rdata/rfc1035.rs
pub fn enable_compression(&mut self) {
self.target.buf.enable_compression()
}
/// Sets the maximum size of the constructed DNS message.
///
/// After this method was called, additional data will not be added to the
/// message if that would result in the message exceeding a size of
/// `limit` bytes. If the message is already larger than `limit` when the
/// method is called, it will _not_ be truncated. That is, you can never
/// actually set a limit smaller than the current message size.
///
/// Note also that the limit only regards the message constructed by the
/// builder itself. If a builder was created atop a buffer that already
/// contained some data, this pre-existing data is not considered.
pub fn set_limit(&mut self, limit: usize) {
self.target.buf.set_limit(limit)
}
/// Sets the amount of data by which to grow the underlying buffer.
///
/// Whenever the buffer runs out of space but the message size limit has
/// not yet been reached, the builder will grow the buffer by at least
/// `page_size` bytes.
///
/// A special case is a page size of zero, in which case the buffer will
/// be grown only once to have enough space to reach the current limit.
pub fn set_page_size(&mut self, page_size: usize) {
self.target.buf.set_page_size(page_size)
}
@@ -179,10 +314,13 @@ impl MessageBuilder {
/// fulfill this requirement with the class assumed to be `Class::In` in
/// the latter case.
///
/// The method will fail if by appending the question the message would
/// exceed its size limit.
///
/// [`Question`]: ../question/struct.Question.html
pub fn push<N: ToDname>(&mut self, question: &Question<N>)
-> Result<(), ShortBuf> {
self.target.push(|target| question.compress(target),
pub fn push<N: ToDname, Q: Into<Question<N>>>(&mut self, question: Q)
-> Result<(), ShortBuf> {
self.target.push(|target| question.into().compress(target),
|counts| counts.inc_qdcount())
}
@@ -204,6 +342,10 @@ impl MessageBuilder {
}
/// Proceeds to building the OPT record.
///
/// Leaves the answer and additional sections empty. Since the method
/// adds the header of the OPT record already, it can fail if there
/// isnt enough space left in the message.
pub fn opt(self) -> Result<OptBuilder, ShortBuf> {
self.additional().opt()
}
@@ -213,8 +355,9 @@ impl MessageBuilder {
/// This method requires a `&mut self` since it may need to update some
/// length values to return a valid message.
///
/// In case the builder was created from a vector with previous content,
/// the returned reference is for the full content of this vector.
/// In case the builder was created from a buffer with pre-existing
/// content, the returned reference is for the complete content of this
/// buffer.
pub fn preview(&mut self) -> &[u8] {
self.target.preview()
}
@@ -226,6 +369,9 @@ impl MessageBuilder {
self.target.unwrap()
}
/// Finishes the messages and returns the bytes value of the message.
///
/// This will result in a message with all three record sections empty.
pub fn freeze(self) -> Bytes {
self.target.freeze()
}
@@ -234,13 +380,18 @@ impl MessageBuilder {
//------------ AnswerBuilder -------------------------------------------------
/// A type for building the answer section of a DNS message.
/// Builds the answer section of a DNS message.
///
/// This type is typically constructed by calling [`answer()`] on a
/// [`MessageBuilder`]. See the [module documentation] for details.
/// This type is typically constructed by calling [`answer`] on a
/// [`MessageBuilder`]. See the [module documentation] for an overview of how
/// to build a message.
///
/// [`answer()`]: struct.MessageBuilder.html#method.answer
/// Once acquired, you can access a messages header or append resource
/// records to the messages answer section with the [`push`] method.
///
/// [`answer`]: struct.MessageBuilder.html#method.answer
/// [`MessageBuilder`]: struct.MessageBuilder.html
/// [`push`]: #method.push
/// [module documentation]: index.html
#[derive(Clone, Debug)]
pub struct AnswerBuilder {
@@ -249,11 +400,22 @@ pub struct AnswerBuilder {
impl AnswerBuilder {
/// Creates a new answer builder from a compser.
/// Creates a new answer builder from a message target.
fn new(target: MessageTarget) -> Self {
AnswerBuilder { target }
}
/// Updates the messages size limit.
///
/// After this method was called, additional data will not be added to the
/// message if that would result in the message exceeding a size of
/// `limit` bytes. If the message is already larger than `limit` when the
/// method is called, it will _not_ be truncated. That is, you can never
/// actually set a limit smaller than the current message size.
///
/// Note also that the limit only regards the message constructed by the
/// builder itself. If a builder was created atop a buffer that already
/// contained some data, this pre-existing data is not considered.
pub fn set_limit(&mut self, limit: usize) {
self.target.buf.set_limit(limit)
}
@@ -268,10 +430,24 @@ impl AnswerBuilder {
self.target.header_mut()
}
/// Returns a snapshot indicating the current state of the message.
///
/// The returned value can be used to later return the message to the
/// state at the time the method was called through the [`rewind`]
/// method.
///
/// [`rewind`]: #method.rewind
pub fn snapshot(&self) -> Snapshot<Self> {
self.target.snapshot()
}
/// Rewinds the message to the state it had at `snapshot`.
///
/// This will truncate the message to the size it had at the time the
/// [`snapshot`] method was called, making it forget all records added
/// since.
///
/// [`snapshot`]: #method.snapshot
pub fn rewind(&mut self, snapshot: Snapshot<Self>) {
self.target.rewind(snapshot)
}
@@ -283,12 +459,13 @@ impl AnswerBuilder {
/// a domain name, class, TTL, and record data or triples leaving out
/// the class which will then be assumed to be `Class::In`.
///
/// If appending the record would result in the message exceeding its
/// size limit, the method will fail.
///
/// [`Record`]: ../record/struct.Record.html
pub fn push<N, D>(&mut self, record: &Record<N, D>)
-> Result<(), ShortBuf>
where N: ToDname,
D: RecordData {
self.target.push(|target| record.compress(target),
pub fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
self.target.push(|target| record.into().compress(target),
|counts| counts.inc_ancount())
}
@@ -303,6 +480,13 @@ impl AnswerBuilder {
}
/// Proceeds to building the OPT record.
///
/// The method will start by adding the record header. Since this may
/// exceed the message limit, the method may fail.
/// If you have saved space for the OPT record via [`set_limit`] earlier,
/// remember to increase the limit again before calling `opt`.
///
/// [`set_limit`]: #method.set_limit
pub fn opt(self) -> Result<OptBuilder, ShortBuf> {
self.additional().opt()
}
@@ -320,11 +504,16 @@ impl AnswerBuilder {
/// Finishes the message and returns the underlying bytes buffer.
///
/// This will result in a message with all three record sections empty.
/// This will result in a message with empty authority and additional
/// sections.
pub fn finish(self) -> BytesMut {
self.target.unwrap()
}
/// Finishes the message and returns the resulting bytes value.
///
/// This will result in a message with empty authority and additional
/// sections.
pub fn freeze(self) -> Bytes {
self.target.freeze()
}
@@ -333,14 +522,18 @@ impl AnswerBuilder {
//------------ AuthorityBuilder ---------------------------------------------
/// A type for building the authority section of a DNS message.
/// Builds the authority section of a DNS message.
///
/// This type can be constructed by calling `authority()` on a
/// [`MessageBuilder`] or [`AnswerBuilder`]. See the [module documentation]
/// for details.
/// for details on constructing messages.
///
/// Once acquired, you can use this type to add records to the authority
/// section of a message via the [`push`] method.
///
/// [`AnswerBuilder`]: struct.AnswerBuilder.html
/// [`MessageBuilder`]: struct.MessageBuilder.html
/// [`push`]: #method.push
/// [module documentation]: index.html
#[derive(Clone, Debug)]
pub struct AuthorityBuilder {
@@ -354,6 +547,17 @@ impl AuthorityBuilder {
AuthorityBuilder { target }
}
/// Updates the messages size limit.
///
/// After this method was called, additional data will not be added to the
/// message if that would result in the message exceeding a size of
/// `limit` bytes. If the message is already larger than `limit` when the
/// method is called, it will _not_ be truncated. That is, you can never
/// actually set a limit smaller than the current message size.
///
/// Note also that the limit only regards the message constructed by the
/// builder itself. If a builder was created atop a buffer that already
/// contained some data, this pre-existing data is not considered.
pub fn set_limit(&mut self, limit: usize) {
self.target.buf.set_limit(limit)
}
@@ -368,10 +572,24 @@ impl AuthorityBuilder {
self.target.header_mut()
}
/// Returns a snapshot indicating the current state of the message.
///
/// The returned value can be used to later return the message to the
/// state at the time the method was called through the [`rewind`]
/// method.
///
/// [`rewind`]: #method.rewind
pub fn snapshot(&self) -> Snapshot<Self> {
self.target.snapshot()
}
/// Rewinds the message to the state it had at `snapshot`.
///
/// This will truncate the message to the size it had at the time the
/// [`snapshot`] method was called, making it forget all records added
/// since.
///
/// [`snapshot`]: #method.snapshot
pub fn rewind(&mut self, snapshot: Snapshot<Self>) {
self.target.rewind(snapshot)
}
@@ -383,12 +601,13 @@ impl AuthorityBuilder {
/// a domain name, class, TTL, and record data or triples leaving out
/// the class which will then be assumed to be `Class::In`.
///
/// If appending the record would result in the message exceeding its
/// size limit, the method will fail.
///
/// [`Record`]: ../record/struct.Record.html
pub fn push<N, D>(&mut self, record: &Record<N, D>)
-> Result<(), ShortBuf>
where N: ToDname,
D: RecordData {
self.target.push(|target| record.compress(target),
pub fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
self.target.push(|target| record.into().compress(target),
|counts| counts.inc_nscount())
}
@@ -398,6 +617,13 @@ impl AuthorityBuilder {
}
/// Proceeds to building the OPT record.
///
/// The method will start by adding the record header. Since this may
/// exceed the message limit, the method may fail.
/// If you have saved space for the OPT record via [`set_limit`] earlier,
/// remember to increase the limit again before calling `opt`.
///
/// [`set_limit`]: #method.set_limit
pub fn opt(self) -> Result<OptBuilder, ShortBuf> {
self.additional().opt()
}
@@ -415,11 +641,14 @@ impl AuthorityBuilder {
/// Finishes the message and returns the underlying bytes buffer.
///
/// This will result in a message with all three record sections empty.
/// This will result in a message with an empty additional section.
pub fn finish(self) -> BytesMut {
self.target.unwrap()
}
/// Finishes the message and returns the resulting bytes value.
///
/// This will result in a message with an empty additional section.
pub fn freeze(self) -> Bytes {
self.target.freeze()
}
@@ -428,15 +657,23 @@ impl AuthorityBuilder {
//------------ AdditionalBuilder --------------------------------------------
/// A type for building the additional section of a DNS message.
/// Builds the additional section of a DNS message.
///
/// This type can be constructed by calling `additional()` on a
/// This type can be constructed by calling `additional` on a
/// [`MessageBuilder`], [`AnswerBuilder`], or [`AuthorityBuilder`]. See the
/// [module documentation] for details.
/// [module documentation] for on overview on building messages.
///
/// Once aquired, you can add records to the additional section via the
/// [`push`] method. If the record you want to add is an OPT record, you
/// can also use the [`OptBuilder`] type which you can acquire via the
/// [`opt`] method.
///
/// [`AnswerBuilder`]: struct.AnswerBuilder.html
/// [`AuthorityBuilder`]: struct.AuthorityBuilder.html
/// [`MessageBuilder`]: struct.MessageBuilder.html
/// [`OptBuilder`]: struct.OptBuilder.html
/// [`push`]: #method.push
/// [`opt`]: #method.opt
/// [module documentation]: index.html
#[derive(Clone, Debug)]
pub struct AdditionalBuilder {
@@ -455,6 +692,17 @@ impl AdditionalBuilder {
self.target.header()
}
/// Updates the messages size limit.
///
/// After this method was called, additional data will not be added to the
/// message if that would result in the message exceeding a size of
/// `limit` bytes. If the message is already larger than `limit` when the
/// method is called, it will _not_ be truncated. That is, you can never
/// actually set a limit smaller than the current message size.
///
/// Note also that the limit only regards the message constructed by the
/// builder itself. If a builder was created atop a buffer that already
/// contained some data, this pre-existing data is not considered.
pub fn set_limit(&mut self, limit: usize) {
self.target.buf.set_limit(limit)
}
@@ -464,10 +712,24 @@ impl AdditionalBuilder {
self.target.header_mut()
}
/// Returns a snapshot indicating the current state of the message.
///
/// The returned value can be used to later return the message to the
/// state at the time the method was called through the [`rewind`]
/// method.
///
/// [`rewind`]: #method.rewind
pub fn snapshot(&self) -> Snapshot<Self> {
self.target.snapshot()
}
/// Rewinds the message to the state it had at `snapshot`.
///
/// This will truncate the message to the size it had at the time the
/// [`snapshot`] method was called, making it forget all records added
/// since.
///
/// [`snapshot`]: #method.snapshot
pub fn rewind(&mut self, snapshot: Snapshot<Self>) {
self.target.rewind(snapshot)
}
@@ -479,16 +741,24 @@ impl AdditionalBuilder {
/// a domain name, class, TTL, and record data or triples leaving out
/// the class which will then be assumed to be `Class::In`.
///
/// If appending the record would result in the message exceeding its
/// size limit, the method will fail.
///
/// [`Record`]: ../record/struct.Record.html
pub fn push<N, D>(&mut self, record: &Record<N, D>)
-> Result<(), ShortBuf>
where N: ToDname,
D: RecordData {
self.target.push(|target| record.compress(target),
|counts| counts.inc_arcount())
pub fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
self.target.push(|target| record.into().compress(target),
|counts| counts.inc_nscount())
}
/// Proceeds to building the OPT record.
///
/// The method will start by adding the record header. Since this may
/// exceed the message limit, the method may fail.
/// If you have saved space for the OPT record via [`set_limit`] earlier,
/// remember to increase the limit again before calling `opt`.
///
/// [`set_limit`]: #method.set_limit
pub fn opt(self) -> Result<OptBuilder, ShortBuf> {
OptBuilder::new(self.target)
}
@@ -505,12 +775,11 @@ impl AdditionalBuilder {
}
/// Finishes the message and returns the underlying bytes buffer.
///
/// This will result in a message with all three record sections empty.
pub fn finish(self) -> BytesMut {
self.target.unwrap()
}
/// Finishes the message and returns the resulting bytes value.
pub fn freeze(self) -> Bytes {
self.target.freeze()
}
@@ -519,6 +788,13 @@ impl AdditionalBuilder {
//------------ OptBuilder ----------------------------------------------------
/// Builds an OPT record as part of the additional section of a DNS message,
///
/// This type can be constructed by calling the `opt` method on a
/// [`MessageBuilder`], [`AnswerBuilder`], [`AuthorityBuilder`], or
/// [`AdditionalBuilder`]. See the [module documentation] for on overview
/// on building messages.
///
#[derive(Clone, Debug)]
pub struct OptBuilder {
target: MessageTarget,
@@ -571,7 +847,8 @@ impl OptBuilder {
let len = self.target.len()
- (self.pos + mem::size_of::<OptHeader>() + 2);
assert!(len <= ::std::u16::MAX as usize);
BigEndian::write_u16(&mut self.target.as_slice_mut()[self.pos..],
let count_pos = self.pos + mem::size_of::<OptHeader>();
BigEndian::write_u16(&mut self.target.as_slice_mut()[count_pos..],
len as u16);
self.target.counts_mut().inc_arcount();
self.target
@@ -614,7 +891,6 @@ impl MessageTarget {
- buf.remaining_mut();
buf.reserve(additional)
}
0u16.compose(&mut buf);
let mut buf = Compressor::from_buf(buf);
HeaderSection::default().compose(&mut buf);
MessageTarget { buf, start }
+8 -7
View File
@@ -88,16 +88,17 @@
pub use self::charstr::{CharStr, CharStrMut};
pub use self::compose::{Compose, Compress, Compressor};
pub use self::header::{Header, HeaderCounts, HeaderSection};
pub use self::message::{Message, RecordSection};
pub use self::message_builder::MessageBuilder;
pub use self::name::{Dname, ParsedDname, RelativeDname};
/*
pub use self::message::{Message, MessageBuf};
pub use self::message_builder::{MessageBuilder, AnswerBuilder,
AuthorityBuilder, AdditionalBuilder};
pub use self::name::{DName, DNameBuf, DNameSlice, ParsedDName};
pub use self::parse::{Parser, ParseError, ParseResult};
pub use self::question::Question;
pub use self::rdata::{GenericRecordData, ParsedRecordData, RecordData};
pub use self::record::{GenericRecord, Record};
*/
pub use self::question::Question;
/*
pub use self::rdata::{GenericRecordData, ParsedRecordData, RecordData};
*/
pub use self::record::{Record};
//--- Modules
+12 -4
View File
@@ -485,9 +485,17 @@ impl hash::Hash for Dname {
//--- Display and Debug
impl fmt::Display for Dname {
/// Formats the domain name.
///
/// This will produce the domain name in common display format without
/// the trailing dot.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for label in self.iter() {
write!(f, ".{}", label)?
let mut iter = self.iter();
write!(f, "{}", iter.next().unwrap())?;
for label in iter {
if !label.is_root() {
write!(f, ".{}", label)?
}
}
Ok(())
}
@@ -495,7 +503,7 @@ impl fmt::Display for Dname {
impl fmt::Debug for Dname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Dname({})", self)
write!(f, "Dname({}.)", self)
}
}
@@ -514,7 +522,7 @@ impl Scan for Dname {
impl Print for Dname {
fn print<W: io::Write>(&self, printer: &mut Printer<W>)
-> Result<(), io::Error> {
write!(printer.item()?, "{}", self)
write!(printer.item()?, "{}.", self)
}
}
+48 -20
View File
@@ -84,12 +84,11 @@ impl Parse for ParsedDname {
// Phase 1: Take labels from the parser until the root label or the
// first compressed label. In the latter case, remember where
// the actual name ended.
let end = loop {
let mut parser = loop {
match LabelType::parse(parser) {
Ok(LabelType::Normal(0)) => {
len += 1;
if len > 255 {
parser.seek(start).unwrap();
return Err(BadParsedDname::LongName.into())
}
let mut res = parser.clone();
@@ -99,24 +98,21 @@ impl Parse for ParsedDname {
}
Ok(LabelType::Normal(label_len)) => {
if let Err(err) = parser.advance(label_len) {
parser.seek(start).unwrap();
return Err(err.into())
}
len += label_len + 1;
if len > 255 {
parser.seek(start).unwrap();
return Err(BadParsedDname::LongName.into())
}
}
Ok(LabelType::Compressed(pos)) => {
let mut parser = parser.clone();
if let Err(err) = parser.seek(pos) {
parser.seek(start).unwrap();
return Err(err.into())
}
break parser.pos()
break parser
}
Err(err) => {
parser.seek(start).unwrap();
return Err(err)
}
}
@@ -124,29 +120,25 @@ impl Parse for ParsedDname {
// Phase 2: Follow offsets so we can get the length.
loop {
match LabelType::parse(parser)? {
match LabelType::parse(&mut parser)? {
LabelType::Normal(0) => {
len += 1;
if len > 255 {
parser.seek(start).unwrap();
return Err(BadParsedDname::LongName.into())
}
break;
}
LabelType::Normal(label_len) => {
if let Err(err) = parser.advance(label_len) {
parser.seek(start).unwrap();
return Err(err.into())
}
len += label_len + 1;
if len > 255 {
parser.seek(start).unwrap();
return Err(BadParsedDname::LongName.into())
}
}
LabelType::Compressed(pos) => {
if let Err(err) = parser.seek(pos) {
parser.seek(start).unwrap();
return Err(err.into())
}
}
@@ -154,10 +146,38 @@ impl Parse for ParsedDname {
}
// Phase 3: Profit
parser.seek(end).unwrap();
let mut res = parser.clone();
res.seek(start).unwrap();
Ok(ParsedDname { parser: res, len, compressed: true })
parser.seek(start).unwrap();
Ok(ParsedDname { parser, len, compressed: true })
}
fn skip(parser: &mut Parser) -> Result<(), Self::Err> {
let mut len = 0;
loop {
match LabelType::parse(parser) {
Ok(LabelType::Normal(0)) => {
len += 1;
if len > 255 {
return Err(BadParsedDname::LongName.into())
}
return Ok(())
}
Ok(LabelType::Normal(label_len)) => {
if let Err(err) = parser.advance(label_len) {
return Err(err.into())
}
len += label_len + 1;
if len > 255 {
return Err(BadParsedDname::LongName.into())
}
}
Ok(LabelType::Compressed(_)) => {
return Ok(())
}
Err(err) => {
return Err(err)
}
}
}
}
}
@@ -268,9 +288,17 @@ impl hash::Hash for ParsedDname {
//--- Display and Debug
impl fmt::Display for ParsedDname {
/// Formats the domain name.
///
/// This will produce the domain name in common display format without
/// the trailing dot.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for label in self.iter() {
write!(f, ".{}", label)?
let mut iter = self.iter();
write!(f, "{}", iter.next().unwrap())?;
for label in iter {
if !label.is_root() {
write!(f, ".{}", label)?
}
}
Ok(())
}
@@ -278,7 +306,7 @@ impl fmt::Display for ParsedDname {
impl fmt::Debug for ParsedDname {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ParsedDname({})", self)
write!(f, "ParsedDname({}.)", self)
}
}
@@ -288,7 +316,7 @@ impl fmt::Debug for ParsedDname {
impl Print for ParsedDname {
fn print<W: io::Write>(&self, printer: &mut Printer<W>)
-> Result<(), io::Error> {
write!(printer.item()?, "{}", self)
write!(printer.item()?, "{}.", self)
}
}
+11
View File
@@ -56,6 +56,14 @@ pub trait ToLabelIter<'a> {
}
}
impl<'a, 'b, N: ToLabelIter<'b>> ToLabelIter<'b> for &'a N {
type LabelIter = N::LabelIter;
fn iter_labels(&'b self) -> Self::LabelIter {
(*self).iter_labels()
}
}
//------------ ToRelativeDname -----------------------------------------------
@@ -88,6 +96,8 @@ pub trait ToRelativeDname: Compose + for<'a> ToLabelIter<'a> {
}
}
impl<'a, N: ToRelativeDname + 'a> ToRelativeDname for &'a N { }
//------------ ToDname -------------------------------------------------------
@@ -121,3 +131,4 @@ pub trait ToDname: Compose + Compress + for<'a> ToLabelIter<'a> {
}
}
impl<'a, N: ToDname + 'a> ToDname for &'a N { }
+11 -1
View File
@@ -26,6 +26,16 @@ pub mod rfc7873;
pub mod rfc7901;
pub mod rfc8145;
pub use self::rfc5001::Nsid;
pub use self::rfc6975::{Dau, Dhu, N3u};
pub use self::rfc7314::Expire;
pub use self::rfc7828::TcpKeepalive;
pub use self::rfc7830::Padding;
pub use self::rfc7871::ClientSubnet;
pub use self::rfc7873::Cookie;
pub use self::rfc7901::Chain;
pub use self::rfc8145::KeyTag;
//------------ Opt -----------------------------------------------------------
@@ -155,7 +165,7 @@ impl OptHeader {
impl Default for OptHeader {
fn default() -> Self {
OptHeader { inner: [0, 41, 0, 0, 0, 0, 0, 0, 0] }
OptHeader { inner: [0, 0, 41, 0, 0, 0, 0, 0, 0] }
}
}
+19 -8
View File
@@ -1,13 +1,15 @@
use std::fmt;
use bytes::BufMut;
use ::iana::{Class, Rtype};
use super::compose::{Compose, Compress, Compressor};
use super::name::ToDname;
use super::parse::{Parse, Parser, ShortBuf};
//------------ Question ------------------------------------------------------
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Question<N> {
pub struct Question<N: ToDname> {
qname: N,
qtype: Rtype,
qclass: Class,
@@ -15,7 +17,7 @@ pub struct Question<N> {
/// # Creation and Conversion
///
impl<N> Question<N> {
impl<N: ToDname> Question<N> {
pub fn new(qname: N, qtype: Rtype, qclass: Class) -> Self {
Question { qname, qtype, qclass }
}
@@ -28,7 +30,7 @@ impl<N> Question<N> {
/// # Field Access
///
impl<N> Question<N> {
impl<N: ToDname> Question<N> {
pub fn qname(&self) -> &N {
&self.qname
}
@@ -45,13 +47,13 @@ impl<N> Question<N> {
//--- From
impl<N> From<(N, Rtype, Class)> for Question<N> {
impl<N: ToDname> From<(N, Rtype, Class)> for Question<N> {
fn from((name, rtype, class): (N, Rtype, Class)) -> Self {
Question::new(name, rtype, class)
}
}
impl<N> From<(N, Rtype)> for Question<N> {
impl<N: ToDname> From<(N, Rtype)> for Question<N> {
fn from((name, rtype): (N, Rtype)) -> Self {
Question::new(name, rtype, Class::In)
}
@@ -60,7 +62,7 @@ impl<N> From<(N, Rtype)> for Question<N> {
//--- Parse, Compose, and Compress
impl<N: Parse> Parse for Question<N> {
impl<N: ToDname + Parse> Parse for Question<N> {
type Err = <N as Parse>::Err;
fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
@@ -72,7 +74,7 @@ impl<N: Parse> Parse for Question<N> {
}
}
impl<N: Compose> Compose for Question<N> {
impl<N: ToDname> Compose for Question<N> {
fn compose_len(&self) -> usize {
self.qname.compose_len() + self.qtype.compose_len()
+ self.qclass.compose_len()
@@ -85,7 +87,7 @@ impl<N: Compose> Compose for Question<N> {
}
}
impl<N: Compress> Compress for Question<N> {
impl<N: ToDname> Compress for Question<N> {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
self.qname.compress(buf)?;
buf.compose(&self.qtype)?;
@@ -93,3 +95,12 @@ impl<N: Compress> Compress for Question<N> {
}
}
//--- Display
impl<N: ToDname + fmt::Display> fmt::Display for Question<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.\t{}\t{}", self.qname, self.qtype, self.qclass)
}
}
+29 -27
View File
@@ -14,7 +14,7 @@ use ::iana::{Class, Rtype};
use ::master::print::{Print, Printer};
//use ::master::scan::{CharSource, Scannable, Scanner};
use super::compose::{Compose, Compress, Compressor};
use super::name::{ParsedDname, ParsedDnameError};
use super::name::{ParsedDname, ParsedDnameError, ToDname};
use super::parse::{Parse, Parser, ShortBuf};
use super::rdata::{ParseRecordData, RecordData};
@@ -76,7 +76,7 @@ use super::rdata::{ParseRecordData, RecordData};
/// [`Rtype`]: ../../iana/enum.Rtype.html
/// [`domain::master`]: ../../master/index.html
#[derive(Clone, Debug)]
pub struct Record<N, D> {
pub struct Record<N: ToDname, D: RecordData> {
name: N,
class: Class,
ttl: u32,
@@ -86,7 +86,7 @@ pub struct Record<N, D> {
/// # Creation and Element Access
///
impl<N, D> Record<N, D> {
impl<N: ToDname, D: RecordData> Record<N, D> {
/// Creates a new record from its parts.
pub fn new(name: N, class: Class, ttl: u32, data: D) -> Self {
Record { name, class, ttl, data }
@@ -142,6 +142,21 @@ impl<N, D> Record<N, D> {
}
//--- From
impl<N: ToDname, D: RecordData> From<(N, Class, u32, D)> for Record<N, D> {
fn from((name, class, ttl, data): (N, Class, u32, D)) -> Self {
Self::new(name, class, ttl, data)
}
}
impl<N: ToDname, D: RecordData> From<(N, u32, D)> for Record<N, D> {
fn from((name, ttl, data): (N, u32, D)) -> Self {
Self::new(name, Class::In, ttl, data)
}
}
//--- Parsable, Compose, and Compressor
impl<D: ParseRecordData> Parse for Option<Record<ParsedDname, D>> {
@@ -167,7 +182,7 @@ impl<D: ParseRecordData> Parse for Option<Record<ParsedDname, D>> {
}
}
impl<N: Compose, D: RecordData> Compose for Record<N, D> {
impl<N: ToDname, D: RecordData> Compose for Record<N, D> {
fn compose_len(&self) -> usize {
self.name.compose_len() + self.data.compose_len() + 10
}
@@ -180,7 +195,7 @@ impl<N: Compose, D: RecordData> Compose for Record<N, D> {
}
}
impl<N: Compress, D: RecordData + Compress> Compress
impl<N: ToDname, D: RecordData + Compress> Compress
for Record<N, D> {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
self.name.compress(buf)?;
@@ -208,7 +223,7 @@ impl<N: Scannable> Scannable for Record<N, MasterRecordData> {
}
*/
impl<N, D> Print for Record<N, D>
impl<N: ToDname, D: RecordData> Print for Record<N, D>
where N: Print, D: RecordData + Print {
fn print<W: io::Write>(&self, printer: &mut Printer<W>)
-> Result<(), io::Error> {
@@ -221,27 +236,12 @@ impl<N, D> Print for Record<N, D>
}
//--- From
impl<N, D> From<(N, Class, u32, D)> for Record<N, D> {
fn from(x: (N, Class, u32, D)) -> Self {
Record::new(x.0, x.1, x.2, x.3)
}
}
impl<N, D> From<(N, u32, D)> for Record<N, D> {
fn from(x: (N, u32, D)) -> Self {
Record::new(x.0, Class::In, x.1, x.2)
}
}
//--- Display and Print
//--- Display
impl<N, D> fmt::Display for Record<N, D>
where N: fmt::Display, D: RecordData + fmt::Display {
where N: ToDname + fmt::Display, D: RecordData + fmt::Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}\t{}\t{}\t{}\t{}",
write!(f, "{}.\t{}\t{}\t{}\t{}",
self.name, self.ttl, self.class, self.data.rtype(),
self.data)
}
@@ -299,7 +299,7 @@ impl RecordHeader<ParsedDname> {
}
}
impl<N> RecordHeader<N> {
impl<N: ToDname> RecordHeader<N> {
/// Returns a reference to the owner of the record.
pub fn name(&self) -> &N {
&self.name
@@ -326,7 +326,7 @@ impl<N> RecordHeader<N> {
}
/// Converts the header into an actual record.
pub fn into_record<D>(self, data: D) -> Record<N, D> {
pub fn into_record<D: RecordData>(self, data: D) -> Record<N, D> {
Record::new(self.name, self.class, self.ttl, data)
}
}
@@ -455,7 +455,9 @@ impl Parse for ParsedRecord {
fn parse(parser: &mut Parser) -> Result<Self, Self::Err> {
let header = RecordHeader::parse(parser)?;
Ok(Self::new(header, parser.clone()))
let data = parser.clone();
parser.advance(header.rdlen() as usize)?;
Ok(Self::new(header, data))
}
}
+1 -1
View File
@@ -29,7 +29,7 @@ pub mod bits;
pub mod iana;
pub mod master;
pub mod rdata;
pub mod resolv;
/*
pub mod utils;
pub mod resolv;
*/
+6 -5
View File
@@ -136,7 +136,7 @@ macro_rules! dname_type {
impl<N: fmt::Display> fmt::Display for $target<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.$field.fmt(f)
write!(f, "{}.", self.$field)
}
}
}
@@ -590,7 +590,7 @@ impl<N> RtypeRecordData for Minfo<N> {
impl<N: fmt::Display> fmt::Display for Minfo<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.rmailbx, self.emailbx)
write!(f, "{}. {}.", self.rmailbx, self.emailbx)
}
}
@@ -714,7 +714,7 @@ impl<N> RtypeRecordData for Mx<N> {
impl<N: fmt::Display> fmt::Display for Mx<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.preference, self.exchange)
write!(f, "{} {}.", self.preference, self.exchange)
}
}
@@ -1013,8 +1013,9 @@ impl<N> RtypeRecordData for Soa<N> {
impl<N: fmt::Display> fmt::Display for Soa<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {} {} {} {} {}", self.mname, self.rname, self.serial,
self.refresh, self.retry, self.expire, self.minimum)
write!(f, "{}. {}. {} {} {} {} {}",
self.mname, self.rname, self.serial, self.refresh, self.retry,
self.expire, self.minimum)
}
}
+5 -7
View File
@@ -22,7 +22,7 @@ use std::path::Path;
use std::str::{self, FromStr, SplitWhitespace};
use std::result;
use std::time::Duration;
use ::bits::name::{self, DNameBuf, DNameSlice};
use ::bits::name::{self, Dname};
//------------ ResolvOptions ------------------------------------------------
@@ -269,7 +269,7 @@ pub struct ResolvConf {
pub servers: Vec<ServerConf>,
/// Search list for host-name lookup.
pub search: Vec<DNameBuf>,
pub search: Vec<Dname>,
/// TODO Sortlist
/// sortlist: ??
@@ -328,7 +328,7 @@ impl ResolvConf {
self.servers.push(ServerConf::new(addr))
}
if self.search.is_empty() {
self.search.push(DNameSlice::root().to_owned())
self.search.push(Dname::root())
}
for server in &mut self.servers {
server.request_timeout = self.timeout
@@ -396,8 +396,7 @@ impl ResolvConf {
}
fn parse_domain(&mut self, mut words: SplitWhitespace) -> Result<()> {
let mut domain = try!(DNameBuf::from_str(try!(next_word(&mut words))));
domain.append(&DNameSlice::root()).unwrap(); // XXX
let domain = try!(Dname::from_str(try!(next_word(&mut words))));
self.search = Vec::new();
self.search.push(domain);
no_more_words(words)
@@ -406,8 +405,7 @@ impl ResolvConf {
fn parse_search(&mut self, words: SplitWhitespace) -> Result<()> {
let mut search = Vec::new();
for word in words {
let mut name = try!(DNameBuf::from_str(word));
name.append(&DNameSlice::root()).unwrap(); // XXX
let name = try!(Dname::from_str(word));
search.push(name)
}
self.search = search;
+3 -1
View File
@@ -213,12 +213,13 @@
//------------ Re-exports ----------------------------------------------------
pub use self::conf::ResolvConf;
pub use self::public::{Query, Resolver};
//pub use self::public::{Query, Resolver};
//------------ Public Modules ------------------------------------------------
pub mod conf;
/*
pub mod error;
pub mod lookup;
@@ -236,3 +237,4 @@ mod request;
mod tcp;
mod transport;
mod udp;
*/