Module domain::base::message_builder
source · Expand description
Building a new DNS message.
The types in this module allow building a DNS message consecutively from
its parts. Since messages consist of five parts, a number of types are
involved. The concept is that you start out with a MessageBuilder
and
work your way step by step through the sections by trading the builder in
for on of another type representing the following section. The sequence
is MessageBuilder
, QuestionBuilder
, AnswerBuilder
,
AuthorityBuilder
, and finally AdditionalBuilder
.
You can skip forward over unwanted sections. You can also go backwards,
but then you’ll loose anything you built before. The naming of the
methods that do these things is consistent across types: builder
takes
you to the message builder. The four methods question
, answer
,
additional
, and authority
progress or return to the respective
section. Finally, finish
completes building.
Each of the section builders offers a push
method to add elements to
the section. For the question section, the method accepts anything that
resembles a Question
while the three record sections except
something that looks like a Record
. Apart from actual values
of these types, tuples of the components also work, such as a pair of a
domain name and a record type for a question or a triple of the owner
name, TTL, and record data for a record. If you already have a question
or record, you can use the push_ref
method to add
The push
method of the record
section builders is also available via the RecordSectionBuilder
trait so you can build code that works with all three record sections.
The AdditionalBuilder
has a special feature that helps building the
OPT record for EDNS. Its opt
method allows a
closure to build this record on the fly via the OptBuilder
type.
Building happens atop any octets builder, so the type of buffer to use for building can be chosen. The module also provides a few helper types that provide optional features for building messages. All of these are wrappers around an octets builder and are octets builders themselves, so you can mix and match.
First, the StreamTarget
builds a message for use with streaming
transport protocols, e.g., TCP, where the actual message is preceded by
a 16 bit length counter. The stream target keeps this counter up-to-date
and makes sure the message doesn’t become longer than what the counter
can provide for.
Two further types, TreeCompressor
and StaticCompressor
, provide
name compression. This is a mechanism to decrease the size of a DNS
message by avoiding repeating domain names: Instead of including a domain
name or suffix of a domain name that has been mentioned already, a pointer
to the position of the original mention is provided. Since this process is
somewhat expensive as you have to remember which names have already been
used, it isn’t enabled by default and provided via separate octets
builders instead which we call compressors.
Currently, there are two different compressors. TreeCompressor
stores
all names it encountered in a binary tree. While it can handle any number
of names, it does require an allocator and therefore cannot be used in a
no_std
environment. StaticCompressor
, meanwhile, has a static table
for up to 24 names. It is thus becoming ineffective on large messages
with lots of different names. However, 24 should be good enough for most
normal messages.
Example
The following example builds a message with both name compression and the stream length and simply puts two A records into it.
use std::str::FromStr;
use domain::base::{
Dname, MessageBuilder, Rtype, StaticCompressor, StreamTarget
};
use domain::rdata::A;
// Make a domain name we can use later on.
let name = Dname::<Vec<u8>>::from_str("example.com").unwrap();
// Create a message builder wrapping a compressor wrapping a stream
// target.
let mut msg = MessageBuilder::from_target(
StaticCompressor::new(
StreamTarget::new_vec()
)
).unwrap();
// Set the RD bit in the header and proceed to the question section.
msg.header_mut().set_rd(true);
let mut msg = msg.question();
// Add a question and proceed to the answer section.
msg.push((&name, Rtype::A)).unwrap();
let mut msg = msg.answer();
// Add two answer and proceed to the additional sections
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 mut msg = msg.additional();
// Add an OPT record.
msg.opt(|opt| {
opt.set_udp_payload_size(4096);
Ok(())
}).unwrap();
// Convert the builder into the actual message.
let target = msg.finish().into_target();
// A stream target can provide access to the data with or without the
// length counter:
let _ = target.as_stream_slice(); // With length
let _ = target.as_dgram_slice(); // Without length
Structs
- Builds the additional section of a DNS message.
- Builds the answer section of a DNS message.
- Builds the authority section of a DNS message.
- Starts building a DNS message.
- Builds an OPT record.
- Builds the question section of a DNS message.
- A domain name compressor that doesn’t require an allocator.
- A builder target for sending messages on stream transports.
- A domain name compressor that uses a tree.
Enums
Traits
- A section that can have records pushed to it.