Module message_builder

Source
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 message

Structs§

AdditionalBuilder
Builds the additional section of a DNS message.
AnswerBuilder
Builds the answer section of a DNS message.
AuthorityBuilder
Builds the authority section of a DNS message.
MessageBuilder
Starts building a DNS message.
MessageTarget
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§

RecordSectionBuilder
Trait for pushing resource records into a section
SectionBuilder
Trait that implements common interface for building message sections