Expand description
Building a new DNS message.
DNS messages consist of five sections. The first, the header section 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 a number of types that can be used to assembling entries in these sections.
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
Questions to be asked of a name server, normally exactly one. You
can add questions using the push method.
Once you are happy with the question section, you can proceed to the
next section, the answer section, by calling the
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
Records.
A call to authority moves on to the
authority section, represented by an AuthorityBuilder. 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.
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 an AdditionalBuilder by calling the
additional method once you are done
with the authority section. Adding records, once again, happens via the
push method.
Once you are done with the additional section, too, you call
finish to retrieve the bytes buffer with
the message data or freeze to get the
Message instead.
Since 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 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.
Since OPT records are part of the additional section, 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.
§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 and empty OPT record setting the UDP payload size.
use std::str::FromStr;
use domain_core::bits::{Dname, MessageBuilder, SectionBuilder, RecordSectionBuilder};
use domain_core::iana::Rtype;
use domain_core::rdata::A;
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 mut msg = msg.opt().unwrap();
msg.set_udp_payload_size(4096);
let _ = msg.freeze(); // get the messageStructs§
- Additional
Builder - Builds the additional section of a DNS message.
- Answer
Builder - Builds the answer section of a DNS message.
- Authority
Builder - Builds the authority section of a DNS message.
- Message
Builder - Starts building a DNS message.
- Message
Target - Underlying data for constructing a DNS message.
- OptBuilder
- Builds an OPT record as part of the additional section of a DNS message,
- Snapshot
- Contains information about the state of a message.
Traits§
- Record
Section Builder - Trait for pushing resource records into a section
- Section
Builder - Trait that implements common interface for building message sections