mirror of
https://github.com/NLnetLabs/domain.git
synced 2026-09-23 18:24:59 +02:00
Bring back dig.
This commit is contained in:
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ----------------------------------------------------
|
||||
|
||||
|
||||
@@ -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
@@ -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 builder’s 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 buffer’s 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
|
||||
/// isn’t 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 message’s header or append resource
|
||||
/// records to the message’s 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 message’s 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 message’s 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 message’s 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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user