domain_core/bits/message_builder.rs
1//! Building a new DNS message.
2//!
3//! DNS messages consist of five sections. The first, the *header section*
4//! contain, among other things, the number of entries in the following four
5//! section which then contain these entries without any further
6//! delimitation. In order to safely build a correct message, it thus needs
7//! to be assembled step by step, entry by entry. This module provides a
8//! number of types that can be used to assembling entries in these sections.
9//!
10//! Message building happens by appending data to a [`BytesMut`] buffer. This
11//! buffer is automatically grown to accomodate the data if necessary. It
12//! does, however, consider the size limit that all DNS messages have. Thus,
13//! when you start building by creating a [`MessageBuilder`], you can pass
14//! an initial buffer size, a size limit, and a strategy for growing to its
15//! [`with_params`][`MessageBuilder::with_params`] function. Alternatively,
16//! you can create the message atop an existing buffer via
17//! [`from_buf`][`MessageBuilder::from_buf`]. In this case you can adjust the
18//! limits via methods such as [`set_limit`][`MessageBuilder::set_limit`].
19//!
20//! All types allow to change the limit later. This is useful if you know
21//! already that your message will have to end with an OPT or TSIG record.
22//! Since for these you also know the size in advance, you can reserve space
23//! by setting a lower limit and increase it only when finally adding those
24//! records.
25//!
26//! Because domain name compression is somewhat expensive, it needs to be
27//! enable explicitely through the
28//! [`enable_compression`][`MessageBuilder::enable_compression`] method.
29//!
30//! The inital [`MessageBuilder`] allows access to the two first sections of
31//! the new message. The header section can be accessed via
32//! [`header`][`MessageBuilder::header`] and
33//! [`header_mut`][`MessageBuilder::header_mut`]. In addition, it is used for
34//! building the *question section* of the message. This section contains
35//! [`Question`]s to be asked of a name server, normally exactly one. You
36//! can add questions using the [`push`][`MessageBuilder::push`] method.
37//!
38//! Once you are happy with the question section, you can proceed to the
39//! next section, the *answer section,* by calling the
40//! [`answer`][`MessageBuilder::answer`] method.
41//! In a response, this section contains those resource records that answer
42//! the question. The section is represented by the [`AnswerBuilder`] type.
43//! It, too, has a [`push`][`AnswerBuilder::push`] method, but for adding
44//! [`Record`]s.
45//!
46//! A call to [`authority`][`AnswerBuilder::authority`] moves on to the
47//! *authority section,* represented by an [`AuthorityBuilder`]. It contains
48//! resource records that allow to identify the name servers that are
49//! authoritative for the records requested in the question. As with the
50//! answer section, [`push`][`AdditionalBuilder`] adds records to this
51//! section.
52//!
53//! The final section is the *additional section.* Here a name server can add
54//! information it believes will help the client to get to the answer it
55//! really wants. Which these are depends on the question and is generally
56//! given in RFCs that define the record types. Unsurprisingly, you will
57//! arrive at an [`AdditionalBuilder`] by calling the
58//! [`additional`][`AuthorityBuilder::additional`] method once you are done
59//! with the authority section. Adding records, once again, happens via the
60//! [`push`][`AdditionalBuilder::push`] method.
61//!
62//! Once you are done with the additional section, too, you call
63//! [`finish`][`AdditionalBuilder::finish`] to retrieve the bytes buffer with
64//! the message data or [`freeze`][`AdditionalBuilder::freeze`] to get the
65//! [`Message`] instead.
66//!
67//! Since some of the sections are empty in many messages – for instance, a
68//! simple request only contains a single question – there are
69//! shortcuts in place to skip over sections. Each type can go to any later
70//! section through the methods named above. Each type also has the `finish`
71//! and `freeze` methods to arrive at the final data quickly.
72//!
73//! There is one more type: [`OptBuilder`]. It can be used to assemble an
74//! OPT record in the additional section. This is helpful because the OPT
75//! record in turn is a sequence of options that need to be assembled one
76//! by one.
77//!
78//! Since OPT records are part of the additional section, an [`OptBuilder`]
79//! can be retrieved from an [`AdditionalBuilder`] via its
80//! [`opt`][`AdditionalBuilder::opt`] method. Options can then be added as
81//! usually via [`push`][`OptBuilder::push`]. Once done, you can return to
82//! the additional section with [`additional`][`OptBuilder::additional`] or,
83//! if your OPT record is the final record, conclude message construction
84//! via [`finish`][`OptBuilder::finish`] or [`freeze`][`OptBuilder::freeze`].
85//!
86//! # Example
87//!
88//! To summarize all of this, here is an example that builds a
89//! response to an A query for example.com that contains two A records and
90//! and empty OPT record setting the UDP payload size.
91//!
92//! ```
93//! use std::str::FromStr;
94//! use domain_core::bits::{Dname, MessageBuilder, SectionBuilder, RecordSectionBuilder};
95//! use domain_core::iana::Rtype;
96//! use domain_core::rdata::A;
97//!
98//! let name = Dname::from_str("example.com.").unwrap();
99//! let mut msg = MessageBuilder::new_udp();
100//! msg.header_mut().set_rd(true);
101//! msg.push((&name, Rtype::A));
102//! let mut msg = msg.answer();
103//! msg.push((&name, 86400, A::from_octets(192, 0, 2, 1))).unwrap();
104//! msg.push((&name, 86400, A::from_octets(192, 0, 2, 2))).unwrap();
105//! let mut msg = msg.opt().unwrap();
106//! msg.set_udp_payload_size(4096);
107//! let _ = msg.freeze(); // get the message
108//! ```
109//!
110//! [`BytesMut`]: ../../../bytes/struct.BytesMut.html
111//! [`AdditionalBuilder`]: struct.AdditionalBuilder.html
112//! [`AdditionalBuilder::opt`]: struct.AdditionalBuilder.html#method.opt
113//! [`AdditionalBuilder::push`]: struct.AdditionalBuilder.html#method.push
114//! [`AdditionalBuilder::finish`]: struct.AdditionalBuilder.html#method.finish
115//! [`AdditionalBuilder::freeze`]: struct.AdditionalBuilder.html#method.freeze
116//! [`AnswerBuilder`]: struct.AnswerBuilder.html
117//! [`AnswerBuilder::authority`]: struct.AnswerBuilder.html#method.authority
118//! [`AnswerBuilder::push`]: struct.AnswerBuilder.html#method.push
119//! [`AuthorityBuilder`]: struct.AuthorityBuilder.html
120//! [`AuthorityBuilder::additional`]: struct.AuthorityBuilder.html#method.additional
121//! [`AuthorityBuilder::push`]: struct.AuthorityBuilder.html#method.push
122//! [`Composer`]: ../compose/Composer.html
123//! [`Message`]: ../message/struct.Messsage.html
124//! [`MessageBuilder`]: struct.MessageBuilder.html
125//! [`MessageBuilder::answer`]: struct.MessageBuilder.html#method.answer
126//! [`MessageBuilder::enable_compression`]: struct.MessageBuilder.html#method.enable_compression
127//! [`MessageBuilder::from_buf`]: struct.MessageBuilder.html#method.from_buf
128//! [`MessageBuilder::header`]: struct.MessageBuilder.html#method.header
129//! [`MessageBuilder::header_mut`]: struct.MessageBuilder.html#method.header_mut
130//! [`MessageBuilder::push`]: struct.MessageBuilder.html#method.push
131//! [`MessageBuilder::with_params`]: struct.MessageBuilder.html#method.with_params
132//! [`MessageBuilder::set_limit`]: struct.MessageBuilder.html#method.set_limit
133//! [`OptBuilder`]: struct.OptBuilder.html
134//! [`OptBuilder::additional`]: struct.OptBuilder.html#method.additional
135//! [`OptBuilder::finish`]: struct.OptBuilder.html#method.finish
136//! [`OptBuilder::freeze`]: struct.OptBuilder.html#method.freeze
137//! [`OptBuilder::push`]: struct.OptBuilder.html#method.push
138//! [`Question`]: ../question/struct.Question.html
139//! [`Record`]: ../record/struct.Record.html
140
141use std::{mem, ops};
142use std::marker::PhantomData;
143use bytes::{BigEndian, BufMut, ByteOrder, BytesMut};
144use iana::opt::OptionCode;
145use super::compose::{Compose, Compress, Compressor};
146use super::header::{Header, HeaderCounts, HeaderSection};
147use super::message::Message;
148use super::name::ToDname;
149use super::opt::{OptData, OptHeader};
150use super::parse::ShortBuf;
151use super::question::Question;
152use super::rdata::RecordData;
153use super::record::Record;
154
155
156//------------ MessageBuilder -----------------------------------------------
157
158/// Starts building a DNS message.
159///
160/// This type starts building a DNS message and allows adding questions to
161/// its question section. See the [module documentation] for an overview of
162/// how to build a message.
163///
164/// Message builders operate atop a [`BytesMut`] byte buffer. There are a
165/// number of functions to create a builder either using an existing
166/// buffer or with a newly created buffer.
167///
168/// Once created, it is possible to access the message header or append
169/// questions to the question section before proceeding to the subsequent
170/// parts of the message.
171///
172/// [module documentation]: index.html
173/// [`BytesMut`]: ../../../bytes/struct.BytesMut.html
174#[derive(Clone, Debug)]
175pub struct MessageBuilder {
176 target: MessageTarget,
177}
178
179
180/// # Creation and Preparation
181///
182impl MessageBuilder {
183 /// Creates a new builder for a UDP message.
184 ///
185 /// The builder will use a new bytes buffer. The buffer will have a
186 /// capacity of 512 bytes and will also be limited to that.
187 ///
188 /// This will result in a UDP message following the original limit. If you
189 /// want to create larger messages, you should signal this through the use
190 /// of EDNS.
191 pub fn new_udp() -> Self {
192 Self::with_params(512, 512, 0)
193 }
194
195 /// Creates a new builder for a TCP message.
196 ///
197 /// The builder will use a new buffer. It will be limited to 65535 bytes,
198 /// starting with the capacity given and also growing by that amount.
199 ///
200 /// Since DNS messages are preceded on TCP by a two octet length
201 /// inicator, the function will add two bytes with zero before the
202 /// message. Once you have completed your message, you can use can set
203 /// these two bytes to the size of the message. But remember that they
204 /// are in network byte order.
205 pub fn new_tcp(capacity: usize) -> Self {
206 let mut buf = BytesMut::with_capacity(capacity + 2);
207 buf.put_u16_be(0);
208 let mut res = Self::from_buf(buf);
209 res.set_limit(::std::u16::MAX as usize);
210 res.set_page_size(capacity);
211 res
212 }
213
214 /// Creates a new message builder using an existing bytes buffer.
215 ///
216 /// The builder’s initial limit will be equal to whatever capacity is
217 /// left in the buffer. As a consequence, the builder will never grow
218 /// beyond that remaining capacity.
219 pub fn from_buf(buf: BytesMut) -> Self {
220 MessageBuilder { target: MessageTarget::from_buf(buf) }
221 }
222
223 /// Creates a message builder with the given capacity.
224 ///
225 /// The builder will have its own newly created bytes buffer. Its inital
226 /// limit will be equal to the capacity of that buffer. This may be larger
227 /// than `capacity`. If you need finer control over the limit, use
228 /// [`with_params`] instead.
229 ///
230 /// [`with_params`]: #method.with_params
231 pub fn with_capacity(capacity: usize) -> Self {
232 Self::from_buf(BytesMut::with_capacity(capacity))
233 }
234
235 /// Creates a new message builder.
236 ///
237 /// A new buffer will be created for this builder. It will initially
238 /// allocate space for at least `initial` bytes. The message will never
239 /// exceed a size of `limit` bytes. Whenever the buffer’s capacity is
240 /// exhausted, the builder will allocate at least another `page_size`
241 /// bytes. If `page_size` is set to `0`, the builder will allocate at
242 /// most once and then enough bytes to have room for the limit.
243 pub fn with_params(initial: usize, limit: usize, page_size: usize)
244 -> Self {
245 let mut res = Self::with_capacity(initial);
246 res.set_limit(limit);
247 res.set_page_size(page_size);
248 res
249 }
250
251 /// Enables support for domain name compression.
252 ///
253 /// After this method is called, the domain names in questions, the owner
254 /// domain names of resource records, and domain names appearing in the
255 /// record data of record types defined in [RFC 1035] will be compressed.
256 ///
257 /// [RFC 1035]: ../../rdata/rfc1035.rs
258 pub fn enable_compression(&mut self) {
259 self.target.buf.enable_compression()
260 }
261
262 /// Sets the maximum size of the constructed DNS message.
263 ///
264 /// After this method was called, additional data will not be added to the
265 /// message if that would result in the message exceeding a size of
266 /// `limit` bytes. If the message is already larger than `limit` when the
267 /// method is called, it will _not_ be truncated. That is, you can never
268 /// actually set a limit smaller than the current message size.
269 ///
270 /// Note also that the limit only regards the message constructed by the
271 /// builder itself. If a builder was created atop a buffer that already
272 /// contained some data, this pre-existing data is not considered.
273 pub fn set_limit(&mut self, limit: usize) {
274 self.target.buf.set_limit(limit)
275 }
276
277 /// Sets the amount of data by which to grow the underlying buffer.
278 ///
279 /// Whenever the buffer runs out of space but the message size limit has
280 /// not yet been reached, the builder will grow the buffer by at least
281 /// `page_size` bytes.
282 ///
283 /// A special case is a page size of zero, in which case the buffer will
284 /// be grown only once to have enough space to reach the current limit.
285 pub fn set_page_size(&mut self, page_size: usize) {
286 self.target.buf.set_page_size(page_size)
287 }
288}
289
290
291/// # Building
292///
293impl MessageBuilder {
294 /// Appends a new question to the message.
295 ///
296 /// This function is generic over anything that can be converted into a
297 /// [`Question`]. In particular, triples of a domain name, a record type,
298 /// and a class as well as pairs of just a domain name and a record type
299 /// fulfill this requirement with the class assumed to be `Class::In` in
300 /// the latter case.
301 ///
302 /// The method will fail if by appending the question the message would
303 /// exceed its size limit.
304 ///
305 /// [`Question`]: ../question/struct.Question.html
306 pub fn push<N: ToDname, Q: Into<Question<N>>>(&mut self, question: Q)
307 -> Result<(), ShortBuf> {
308 self.target.push(|target| question.into().compress(target),
309 |counts| counts.inc_qdcount())
310 }
311
312 /// Proceeds to building the answer section.
313 pub fn answer(self) -> AnswerBuilder {
314 AnswerBuilder::new(self.target)
315 }
316
317 /// Proceeds to building the authority section, skipping the answer.
318 pub fn authority(self) -> AuthorityBuilder {
319 self.answer().authority()
320 }
321
322 /// Proceeds to building the additional section.
323 ///
324 /// Leaves the answer and additional sections empty.
325 pub fn additional(self) -> AdditionalBuilder {
326 self.answer().authority().additional()
327 }
328}
329
330impl SectionBuilder for MessageBuilder {
331 fn into_target(self) -> MessageTarget { self.target }
332 fn get_target(&self) -> &MessageTarget { &self.target }
333 fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
334}
335
336//------------ AnswerBuilder -------------------------------------------------
337
338/// Builds the answer section of a DNS message.
339///
340/// This type is typically constructed by calling [`answer`] on a
341/// [`MessageBuilder`]. See the [module documentation] for an overview of how
342/// to build a message.
343///
344/// Once acquired, you can access a message’s header or append resource
345/// records to the message’s answer section with the [`push`] method.
346///
347/// [`answer`]: struct.MessageBuilder.html#method.answer
348/// [`MessageBuilder`]: struct.MessageBuilder.html
349/// [`push`]: #method.push
350/// [module documentation]: index.html
351#[derive(Clone, Debug)]
352pub struct AnswerBuilder {
353 target: MessageTarget,
354}
355
356
357impl AnswerBuilder {
358 /// Creates a new answer builder from a message target.
359 fn new(target: MessageTarget) -> Self {
360 AnswerBuilder { target }
361 }
362
363 /// Proceeds to building the authority section.
364 pub fn authority(self) -> AuthorityBuilder {
365 AuthorityBuilder::new(self.target)
366 }
367
368 /// Proceeds to building the additional section, skipping authority.
369 pub fn additional(self) -> AdditionalBuilder {
370 self.authority().additional()
371 }
372
373 /// Proceeds to building the OPT record.
374 ///
375 /// The method will start by adding the record header. Since this may
376 /// exceed the message limit, the method may fail.
377 /// If you have saved space for the OPT record via [`set_limit`] earlier,
378 /// remember to increase the limit again before calling `opt`.
379 ///
380 /// [`set_limit`]: #method.set_limit
381 pub fn opt(self) -> Result<OptBuilder, ShortBuf> where Self: Sized {
382 OptBuilder::new(self.into_target())
383 }
384}
385
386impl SectionBuilder for AnswerBuilder {
387 fn into_target(self) -> MessageTarget { self.target }
388 fn get_target(&self) -> &MessageTarget { &self.target }
389 fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
390}
391
392impl RecordSectionBuilder for AnswerBuilder {
393 fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
394 where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
395 self.target.push(|target| record.into().compress(target),
396 |counts| counts.inc_ancount())
397 }
398}
399
400
401//------------ AuthorityBuilder ---------------------------------------------
402
403/// Builds the authority section of a DNS message.
404///
405/// This type can be constructed by calling `authority()` on a
406/// [`MessageBuilder`] or [`AnswerBuilder`]. See the [module documentation]
407/// for details on constructing messages.
408///
409/// Once acquired, you can use this type to add records to the authority
410/// section of a message via the [`push`] method.
411///
412/// [`AnswerBuilder`]: struct.AnswerBuilder.html
413/// [`MessageBuilder`]: struct.MessageBuilder.html
414/// [`push`]: #method.push
415/// [module documentation]: index.html
416#[derive(Clone, Debug)]
417pub struct AuthorityBuilder {
418 target: MessageTarget,
419}
420
421
422impl AuthorityBuilder {
423 /// Creates a new authority builder from a compser.
424 fn new(target: MessageTarget) -> Self {
425 AuthorityBuilder { target }
426 }
427
428 /// Proceeds to building the additional section.
429 pub fn additional(self) -> AdditionalBuilder {
430 AdditionalBuilder::new(self.target)
431 }
432
433 /// Proceeds to building the OPT record.
434 ///
435 /// The method will start by adding the record header. Since this may
436 /// exceed the message limit, the method may fail.
437 /// If you have saved space for the OPT record via [`set_limit`] earlier,
438 /// remember to increase the limit again before calling `opt`.
439 ///
440 /// [`set_limit`]: #method.set_limit
441 pub fn opt(self) -> Result<OptBuilder, ShortBuf> where Self: Sized {
442 OptBuilder::new(self.into_target())
443 }
444}
445
446impl SectionBuilder for AuthorityBuilder {
447 fn into_target(self) -> MessageTarget { self.target }
448 fn get_target(&self) -> &MessageTarget { &self.target }
449 fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
450}
451
452impl RecordSectionBuilder for AuthorityBuilder {
453 fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
454 where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
455 self.target.push(|target| record.into().compress(target),
456 |counts| counts.inc_nscount())
457 }
458}
459
460
461//------------ AdditionalBuilder --------------------------------------------
462
463/// Builds the additional section of a DNS message.
464///
465/// This type can be constructed by calling `additional` on a
466/// [`MessageBuilder`], [`AnswerBuilder`], or [`AuthorityBuilder`]. See the
467/// [module documentation] for on overview on building messages.
468///
469/// Once aquired, you can add records to the additional section via the
470/// [`push`] method. If the record you want to add is an OPT record, you
471/// can also use the [`OptBuilder`] type which you can acquire via the
472/// [`opt`] method.
473///
474/// [`AnswerBuilder`]: struct.AnswerBuilder.html
475/// [`AuthorityBuilder`]: struct.AuthorityBuilder.html
476/// [`MessageBuilder`]: struct.MessageBuilder.html
477/// [`OptBuilder`]: struct.OptBuilder.html
478/// [`push`]: #method.push
479/// [`opt`]: #method.opt
480/// [module documentation]: index.html
481#[derive(Clone, Debug)]
482pub struct AdditionalBuilder {
483 target: MessageTarget,
484}
485
486
487impl AdditionalBuilder {
488 /// Creates a new additional builder from a compser.
489 fn new(target: MessageTarget) -> Self {
490 AdditionalBuilder { target }
491 }
492
493 /// Proceeds to building the OPT record.
494 ///
495 /// The method will start by adding the record header. Since this may
496 /// exceed the message limit, the method may fail.
497 /// If you have saved space for the OPT record via [`set_limit`] earlier,
498 /// remember to increase the limit again before calling `opt`.
499 ///
500 /// [`set_limit`]: #method.set_limit
501 pub fn opt(self) -> Result<OptBuilder, ShortBuf> where Self: Sized {
502 OptBuilder::new(self.into_target())
503 }
504}
505
506impl SectionBuilder for AdditionalBuilder {
507 fn into_target(self) -> MessageTarget { self.target }
508 fn get_target(&self) -> &MessageTarget { &self.target }
509 fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
510}
511
512impl RecordSectionBuilder for AdditionalBuilder {
513 fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
514 where N: ToDname, D: RecordData, R: Into<Record<N, D>> {
515 self.target.push(|target| record.into().compress(target),
516 |counts| counts.inc_nscount())
517 }
518}
519
520//------------ OptBuilder ----------------------------------------------------
521
522/// Builds an OPT record as part of the additional section of a DNS message,
523///
524/// This type can be constructed by calling the `opt` method on any other
525/// builder type. See the [module documentation] for on overview
526/// on building messages.
527///
528/// As OPT records are part of the additional section, this type will, when
529/// constructed proceed to this section and append an OPT record without any
530/// options to it. Options can be appened via the [`push`] method.
531///
532/// The type also deref-muts to [`OptHeader`] allowing you to modify the
533/// header’s fields such as setting the
534/// [UDP payload size][`OptHeader::set_udp_payload_size`] or the
535/// [DO bit][`OptHeader::set_dnssec_ok`].
536///
537/// Once you have adjusted the OPT record to your liking, you can return to
538/// the additional section via [`additional`]. Note, however, that the OPT
539/// record should be the last record except for a possible TSIG record. You
540/// can also finish the message via [`finish`] or [`freeze`].
541///
542/// [module documentation]: index.html
543/// [`OptHeader`]: ../opt/struct.OptHeader.html
544/// [`additional`]: #method.additional
545/// [`finish`]: #method.finish
546/// [`freeze`]: #method.freeze
547/// [`push`]: #method.push
548/// [`OptHeader::set_udp_payload_size`]: ../opt/struct.OptHeader.html#method.set_udp_payload_size
549/// [`OptHeader::set_dnssec_ok`]: ../opt/struct.OptHeader.html#method.set_dnssec_ok
550#[derive(Clone, Debug)]
551pub struct OptBuilder {
552 target: MessageTarget,
553
554 /// The position of in `target` of the start of the OPT record.
555 pos: usize,
556}
557
558impl OptBuilder {
559 /// Creates a new OPT builder atop the given target.
560 ///
561 /// This appends the OPT header to the message and increases the
562 /// ARCOUNT of the message.
563 fn new(mut target: MessageTarget) -> Result<Self, ShortBuf> {
564 let pos = target.len();
565 target.compose(&OptHeader::default())?;
566 target.compose(&0u16)?;
567 target.counts_mut().inc_arcount();
568 Ok(OptBuilder { pos, target })
569 }
570
571 /// Pushes an option to the OPT record.
572 ///
573 /// The method is generic over anything that implements the `OptData`
574 /// trait representing an option. Alternatively, most of these types
575 /// provide a `push` associated function that allows to construct an
576 /// option directly into a record from its data.
577 pub fn push<O: OptData>(&mut self, option: &O) -> Result<(), ShortBuf> {
578 self.target.compose(&option.code())?;
579 let len = option.compose_len();
580 assert!(len <= ::std::u16::MAX as usize);
581 self.target.compose(&(len as u16))?;
582 self.target.compose(option)?;
583 self.complete();
584 Ok(())
585 }
586
587 /// Builds an option into the record.
588 ///
589 /// The option will have the option code `code`. Its data will be `len`
590 /// octets long and appened to the record via the `op` closure.
591 pub(super) fn build<F>(&mut self, code: OptionCode, len: u16, op: F)
592 -> Result<(), ShortBuf>
593 where F: FnOnce(&mut Compressor)
594 -> Result<(), ShortBuf> {
595 self.target.compose(&code)?;
596 self.target.compose(&len)?;
597 op(&mut self.target.buf)?;
598 self.complete();
599 Ok(())
600 }
601
602 /// Completes the OPT record and returns to the additional section builder.
603 pub fn additional(self) -> AdditionalBuilder {
604 AdditionalBuilder::new(self.target)
605 }
606
607 /// Completes building the OPT record.
608 ///
609 /// This will update the RDLEN field of the record header.
610 fn complete(&mut self) {
611 let len = self.target.len()
612 - (self.pos + mem::size_of::<OptHeader>() + 2);
613 assert!(len <= ::std::u16::MAX as usize);
614 let count_pos = self.pos + mem::size_of::<OptHeader>();
615 BigEndian::write_u16(&mut self.target.as_slice_mut()[count_pos..],
616 len as u16);
617 }
618}
619
620impl SectionBuilder for OptBuilder {
621 fn into_target(self) -> MessageTarget { self.target }
622 fn get_target(&self) -> &MessageTarget { &self.target }
623 fn get_target_mut(&mut self) -> &mut MessageTarget { &mut self.target }
624}
625
626impl ops::Deref for OptBuilder {
627 type Target = OptHeader;
628
629 fn deref(&self) -> &Self::Target {
630 OptHeader::for_record_slice(&self.target.as_slice()[self.pos..])
631 }
632}
633
634impl ops::DerefMut for OptBuilder {
635 fn deref_mut(&mut self) -> &mut Self::Target {
636 OptHeader::for_record_slice_mut(&mut self.target.as_slice_mut()
637 [self.pos..])
638 }
639}
640
641
642//------------ MessageTarget -------------------------------------------------
643
644/// Underlying data for constructing a DNS message.
645///
646/// This private type does all the heavy lifting for constructing messages.
647#[derive(Clone, Debug)]
648pub struct MessageTarget {
649 buf: Compressor,
650 start: usize,
651}
652
653
654impl MessageTarget {
655 /// Creates a new message target atop a given buffer.
656 fn from_buf(mut buf: BytesMut) -> Self {
657 let start = buf.len();
658 if buf.remaining_mut() < mem::size_of::<HeaderSection>() {
659 let additional = mem::size_of::<HeaderSection>()
660 - buf.remaining_mut();
661 buf.reserve(additional)
662 }
663 let mut buf = Compressor::from_buf(buf);
664 HeaderSection::default().compose(&mut buf);
665 MessageTarget { buf, start }
666 }
667
668 /// Returns a reference to the message’s header.
669 fn header(&self) -> &Header {
670 Header::for_message_slice(self.buf.so_far())
671 }
672
673 /// Returns a mutable reference to the message’s header.
674 fn header_mut(&mut self) -> &mut Header {
675 Header::for_message_slice_mut(self.buf.so_far_mut())
676 }
677
678 fn counts(&self) -> &HeaderCounts {
679 HeaderCounts::for_message_slice(self.buf.so_far())
680 }
681
682 /// Returns a mutable reference to the message’s header counts.
683 fn counts_mut(&mut self) -> &mut HeaderCounts {
684 HeaderCounts::for_message_slice_mut(self.buf.so_far_mut())
685 }
686
687 /// Pushes something to the end of the message.
688 ///
689 /// There’s two closures here. The first one, `composeop` actually
690 /// writes the data. The second, `incop` increments the counter in the
691 /// messages header to reflect the new element.
692 fn push<O, I, E>(&mut self, composeop: O, incop: I) -> Result<(), E>
693 where O: FnOnce(&mut Compressor) -> Result<(), E>,
694 I: FnOnce(&mut HeaderCounts) {
695 composeop(&mut self.buf).map(|()| incop(self.counts_mut()))
696 }
697
698 fn snapshot<T>(&self) -> Snapshot<T> {
699 Snapshot {
700 pos: self.buf.len(),
701 counts: *self.counts(),
702 marker: PhantomData,
703 }
704 }
705
706 fn rewind<T>(&mut self, snapshot: &Snapshot<T>) {
707 self.buf.truncate(snapshot.pos);
708 self.counts_mut().set(snapshot.counts);
709 }
710
711 /// Returns a reference to the message assembled so far.
712 ///
713 /// In case the builder was created from a buffer with pre-existing
714 /// content, the returned reference is for the complete content of this
715 /// buffer.
716 fn preview(&self) -> &[u8] {
717 self.buf.as_slice()
718 }
719
720 fn prelude(&self) -> &[u8] {
721 &self.buf.as_slice()[..self.start]
722 }
723
724 fn prelude_mut(&mut self) -> &mut [u8] {
725 &mut self.buf.as_slice_mut()[..self.start]
726 }
727
728 fn unwrap(self) -> BytesMut {
729 self.buf.unwrap()
730 }
731
732 fn freeze(self) -> Message {
733 let bytes = if self.start == 0 {
734 self.buf.unwrap().freeze()
735 }
736 else {
737 self.buf.unwrap().freeze().slice_from(self.start)
738 };
739 unsafe { Message::from_bytes_unchecked(bytes) }
740 }
741}
742
743impl ops::Deref for MessageTarget {
744 type Target = Compressor;
745
746 fn deref(&self) -> &Self::Target {
747 &self.buf
748 }
749}
750
751impl ops::DerefMut for MessageTarget {
752 fn deref_mut(&mut self) -> &mut Self::Target {
753 &mut self.buf
754 }
755}
756
757
758//------------ Snapshot ------------------------------------------------------
759
760/// Contains information about the state of a message.
761///
762/// This type is returned by the `snapshot` method of the various builders and
763/// allows to later return to that state through the `rewind` method.
764#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
765pub struct Snapshot<T> {
766 pos: usize,
767 counts: HeaderCounts,
768 marker: PhantomData<T>,
769}
770
771//------------ SectionBuilder ------------------------------------------------
772
773/// Trait that implements common interface for building message sections
774pub trait SectionBuilder : Sized {
775 /// Updates the message’s size limit.
776 ///
777 /// After this method was called, additional data will not be added to the
778 /// message if that would result in the message exceeding a size of
779 /// `limit` bytes. If the message is already larger than `limit` when the
780 /// method is called, it will _not_ be truncated. That is, you can never
781 /// actually set a limit smaller than the current message size.
782 ///
783 /// Note also that the limit only regards the message constructed by the
784 /// builder itself. If a builder was created atop a buffer that already
785 /// contained some data, this pre-existing data is not considered.
786 fn set_limit(&mut self, limit: usize) {
787 self.get_target_mut().buf.set_limit(limit)
788 }
789
790 /// Returns a reference to the messages header.
791 fn header(&self) -> &Header {
792 self.get_target().header()
793 }
794
795 /// Returns a mutable reference to the messages header.
796 fn header_mut(&mut self) -> &mut Header {
797 self.get_target_mut().header_mut()
798 }
799
800 /// Returns a reference to the message assembled so far.
801 ///
802 /// In case the builder was created from a buffer with pre-existing
803 /// content, the returned reference is for the complete content of this
804 /// buffer.
805 fn preview(&self) -> &[u8] {
806 self.get_target().preview()
807 }
808
809 /// Returns a reference to the slice preceeding the message.
810 ///
811 /// The slice is may be empty.
812 fn prelude(&self) -> &[u8] {
813 self.get_target().prelude()
814 }
815
816 /// Returns a mutable reference to the slice preceeding the message.
817 fn prelude_mut(&mut self) -> &mut [u8] {
818 self.get_target_mut().prelude_mut()
819 }
820
821 /// Finishes the message and returns the underlying bytes buffer.
822 ///
823 /// This will result in a message with empty authority and additional
824 /// sections.
825 fn finish(self) -> BytesMut {
826 self.into_target().unwrap()
827 }
828
829 /// Finishes the message and returns the resulting bytes value.
830 ///
831 /// This will result in a message with empty authority and additional
832 /// sections.
833 fn freeze(self) -> Message {
834 self.into_target().freeze()
835 }
836
837 /// Returns a snapshot indicating the current state of the message.
838 ///
839 /// The returned value can be used to later return the message to the
840 /// state at the time the method was called through the [`rewind`]
841 /// method.
842 ///
843 /// [`rewind`]: #method.rewind
844 fn snapshot(&self) -> Snapshot<Self> {
845 self.get_target().snapshot()
846 }
847
848 /// Rewinds the message to the state it had at `snapshot`.
849 ///
850 /// This will truncate the message to the size it had at the time the
851 /// [`snapshot`] method was called, making it forget all records added
852 /// since.
853 ///
854 /// [`snapshot`]: #method.snapshot
855 fn rewind(&mut self, snapshot: &Snapshot<Self>) {
856 self.get_target_mut().rewind(snapshot)
857 }
858
859 /// Converts into target
860 fn into_target(self) -> MessageTarget;
861
862 /// Returns message target
863 fn get_target(&self) -> &MessageTarget;
864
865 /// Returns message target
866 fn get_target_mut(&mut self) -> &mut MessageTarget;
867}
868
869/// Trait for pushing resource records into a section
870pub trait RecordSectionBuilder : SectionBuilder {
871 /// Appends a new resource record to the section.
872 ///
873 /// This method is generic over anything that can be converted into a
874 /// [`Record`]. In particular, you can use four-tuples consisting of
875 /// a domain name, class, TTL, and record data or triples leaving out
876 /// the class which will then be assumed to be `Class::In`.
877 ///
878 /// If appending the record would result in the message exceeding its
879 /// size limit, the method will fail.
880 ///
881 /// [`Record`]: ../record/struct.Record.html
882 fn push<N, D, R>(&mut self, record: R) -> Result<(), ShortBuf>
883 where N: ToDname, D: RecordData, R: Into<Record<N, D>>;
884}
885
886//============ Testing ======================================================
887
888#[cfg(test)]
889mod test {
890 use std::str::FromStr;
891 use super::*;
892 use rdata::*;
893 use bits::name::*;
894 use bits::rdata::*;
895 use bits::message::*;
896
897 fn get_built_message() -> Message {
898 let msg = MessageBuilder::with_capacity(512);
899 let mut msg = msg.answer();
900 msg.push((Dname::from_str("foo.example.com.").unwrap(), 86000,
901 Cname::new(Dname::from_str("baz.example.com.")
902 .unwrap()))).unwrap();
903 let mut msg = msg.authority();
904 msg.push((Dname::from_str("bar.example.com.").unwrap(), 86000,
905 Cname::new(Dname::from_str("baz.example.com.")
906 .unwrap()))).unwrap();
907 msg.freeze()
908 }
909
910 #[test]
911 fn build_message() {
912 let msg = get_built_message();
913 assert_eq!(1, msg.header_counts().ancount());
914 assert_eq!(1, msg.header_counts().nscount());
915 }
916}