domain_core/bits/compose.rs
1//! Assembling wire-format DNS data.
2//!
3//! Assembling DNS data for transmission over the wire is being called
4//! *composing* to distinguish it from other procedures that turn data into
5//! some output such as formatting it into human-readable text.
6//!
7//! Data is being assembled directly into values implementing the [`BufMut`]
8//! trait. Because such buffers do not reallocate, the overall size of the
9//! assembled data needs to be known beforehand. This module provides the
10//! trait [`Compose`] for types that know how to compose themselves into a
11//! buffer.
12//!
13//! There is, however, the matter of domain name compression which allows a
14//! domain name to indicate that it continues elsewhere in an assembled
15//! message. A consequence is that for a given name, the length of its
16//! assembled representation depends on what is present in the message
17//! already and thus cannot be given in general.
18//!
19//! Because of this differing behaviour when using domain name compression,
20//! we call the process of assembling a messgage *compressing* instead.
21//! Consequently, the module also defines a trait [`Compress`] for type that
22//! know how to compress itself. This happens atop a helper type
23//! [`Compressor`] that wraps a [`BytesMut`] and all the information
24//! necessary for compressing names.
25//!
26//!
27//! [`BufMut`]: ../../../bytes/trait.BufMut.html
28//! [`BytesMut`]: ../../../bytes/struct.BytesMut.html
29//! [`Compose`]: trait.Compose.html
30//! [`Compress`]: trait.Compress.html
31//! [`Compressor`]: struct.Compressor.html
32
33use std::ops;
34use std::collections::HashMap;
35use std::net::{Ipv4Addr, Ipv6Addr};
36use bytes::{BufMut, Bytes, BytesMut};
37use super::name::{Dname, Label, ToDname};
38use super::parse::ShortBuf;
39
40
41//------------ Compose -------------------------------------------------------
42
43/// A type that knows how to compose itself.
44///
45/// The term ‘composing’ refers to the process of creating a DNS wire-format
46/// representation of a value’s data. This happens by appending appending
47/// this data to the end of a type implementing the [`BufMut`] trait.
48///
49/// [`BufMut`]: ../../../bytes/trait.BufMut.html
50pub trait Compose {
51 /// Returns the number of bytes this value will need without compression.
52 fn compose_len(&self) -> usize;
53
54 /// Appends the uncompressed representation of this value to `buf`.
55 ///
56 /// An implementation may assume that the buffer has at least as many
57 /// bytes remaining as the amount a call to `compose_len()` would return
58 /// right now. If that’s not the case, the implementation should panic.
59 /// That is, the implementation can use `buf`‘s `put_*()` methods
60 /// unchecked.
61 fn compose<B: BufMut>(&self, buf: &mut B);
62}
63
64impl<'a, C: Compose> Compose for &'a C {
65 fn compose_len(&self) -> usize {
66 (*self).compose_len()
67 }
68
69 fn compose<B: BufMut>(&self, buf: &mut B) {
70 (*self).compose(buf)
71 }
72}
73
74
75impl Compose for i8 {
76 fn compose_len(&self) -> usize {
77 1
78 }
79
80 fn compose<B: BufMut>(&self, buf: &mut B) {
81 buf.put_i8(*self)
82 }
83}
84
85impl Compose for u8 {
86 fn compose_len(&self) -> usize {
87 1
88 }
89
90 fn compose<B: BufMut>(&self, buf: &mut B) {
91 buf.put_u8(*self)
92 }
93}
94
95impl Compose for i16 {
96 fn compose_len(&self) -> usize {
97 2
98 }
99
100 fn compose<B: BufMut>(&self, buf: &mut B) {
101 buf.put_i16_be(*self)
102 }
103}
104
105impl Compose for u16 {
106 fn compose_len(&self) -> usize {
107 2
108 }
109
110 fn compose<B: BufMut>(&self, buf: &mut B) {
111 buf.put_u16_be(*self)
112 }
113}
114
115impl Compose for i32 {
116 fn compose_len(&self) -> usize {
117 4
118 }
119
120 fn compose<B: BufMut>(&self, buf: &mut B) {
121 buf.put_i32_be(*self)
122 }
123}
124
125impl Compose for u32 {
126 fn compose_len(&self) -> usize {
127 4
128 }
129
130 fn compose<B: BufMut>(&self, buf: &mut B) {
131 buf.put_u32_be(*self)
132 }
133}
134
135impl Compose for [u8] {
136 fn compose_len(&self) -> usize {
137 self.len()
138 }
139
140 fn compose<B: BufMut>(&self, buf: &mut B) {
141 buf.put_slice(self)
142 }
143}
144
145impl Compose for Bytes {
146 fn compose_len(&self) -> usize {
147 self.len()
148 }
149
150 fn compose<B: BufMut>(&self, buf: &mut B) {
151 buf.put_slice(self.as_ref())
152 }
153}
154
155impl Compose for Ipv4Addr {
156 fn compose_len(&self) -> usize {
157 4
158 }
159
160 fn compose<B: BufMut>(&self, buf: &mut B) {
161 buf.put_slice(&self.octets())
162 }
163}
164
165impl Compose for Ipv6Addr {
166 fn compose_len(&self) -> usize {
167 16
168 }
169
170 fn compose<B: BufMut>(&self, buf: &mut B) {
171 buf.put_slice(&self.octets())
172 }
173}
174
175
176//------------ Compress ------------------------------------------------------
177
178/// A type that knows how to compress itself.
179///
180/// The term `compressing` refers to the process of producing the DNS
181/// wire-format representation of a value’s data allowing it to optionally
182/// employ domain name compression.
183///
184/// Because [`BufMut`] doesn’t allow looking back at the data added to the
185/// message before, compression cannot be implemented using just [`Compose`].
186/// Instead, a special type, [`Compressor`] is provided that implements all
187/// the necessary logic for name compression.
188///
189/// `Compress` should only be implemented for domain name types or types that
190/// contain or may contain domain names and want to support name compression.
191/// For all other types, [`Compressor::compose`] uses their [`Compose`]
192/// implementation for appending.
193///
194/// [`BufMut`]: ../../../bytes/trait.BufMut.html
195/// [`Compose`]: trait.Compose.html
196/// [`Compressor`]: struct.Compressor.html
197/// [`Compressor::compose`]: struct.Compressor.html#method.compose
198pub trait Compress {
199 /// Appends the wire-format representation of the value to `buf`.
200 ///
201 /// If `buf` does not have enough space available for appending the
202 /// representation, the method returns an error. If this happens, some
203 /// data may have been appended to the buffer.
204 ///
205 /// For implementers of composite types, this means that they can simply
206 /// compress or compose their consitutent types onto `buf` bailing out
207 /// if that fails. There is no need to truncate `buf` back to its prior
208 /// state on failure.
209 fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf>;
210}
211
212impl<'a, C: Compress + 'a> Compress for &'a C {
213 fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
214 (*self).compress(buf)
215 }
216}
217
218
219//------------ Compressor ----------------------------------------------------
220
221/// A buffer for composing a compressed DNS message.
222///
223/// This type wraps a [`BytesMut`] value into which it composes a message,
224/// growing it as necessary. It provides an implementation for [`BufMut`]
225/// allowing it to be used like any other buffer. In addition, it provides
226/// special handling for types that implement [`Compose`] via the
227/// [`compose`][`Compressor::compose`] method, appending them if there’s
228/// enough space.
229///
230/// The whole point of this type is, of course, name compression. This is
231/// being provided via the [`compress_name`] method which appends any domain
232/// name. Since compression is actually rather expensive as we need to keep
233/// track of names that have been written so far, it needs to be explicitely
234/// enabled via the [`enable_compression`] method.
235///
236/// Two more methods for tweaking the behaviour of `Compressor` are available.
237/// The maximum size of a message can be set via the [`set_limit`]. A value
238/// will grow its underlying buffer as needed up to at most this size. It
239/// will re-allocate memory if necessary by the amount set through
240/// [`set_page_size`]. By default, or if the page size is set to 0, it will
241/// only allocate exactly once to have enough space to reach the current
242/// limit.
243///
244/// Once you are done composing your message, you can either extract the
245/// underlying [`BytesMut`] via [`unwrap`] or get it as a frozen [`Bytes`]
246/// directly via [`freeze`].
247///
248/// Note: Name compression is currently implemented in a rather naive way
249/// by simply storing each compressed name’s position in a hash map
250/// (also considering all its parents). This can probably be optimized.
251/// In addition, this approach doesn’t
252/// consider non-compressed names (since they are appended via their
253/// `Compose` implementation).
254///
255/// [`BufMut`]: ../../../bytes/trait.BufMut.html
256/// [`Bytes`]: ../../../bytes/struct.Bytes.html
257/// [`BytesMut`]: ../../../bytes/struct.BytesMut.html
258/// [`Compose`]: trait.Compose.html
259/// [`Compressor::compose`]: #method.compose
260/// [`compress_name`]: #method.compress_name
261/// [`enable_compression`]: #method.enable_compression
262/// [`freeze`]: #method.freeze
263/// [`set_limit`]: #method.set_limit
264/// [`set_page_size`]: #method.set_page_size
265/// [`unwrap`]: #method.unwrap
266#[derive(Clone, Debug, )]
267pub struct Compressor {
268 /// The bytes buffer we work on.
269 buf: BytesMut,
270
271 /// Index of where in `buf` the message starts.
272 start: usize,
273
274 /// The maximum size of `buf` in bytes.
275 ///
276 /// This is is whatever is set via `set_limit` plus `start`.
277 limit: usize,
278
279 /// The number of bytes to grow each time we run out of space.
280 ///
281 /// If this is 0, we grow exactly once to the size given by `limit`.
282 page_size: usize,
283
284 /// The optional compression map.
285 ///
286 /// This keeps the position relative to the start of the message for each
287 /// name we’ve ever written.
288 map: Option<HashMap<Dname, u16>>,
289}
290
291impl Compressor {
292 /// Creates a compressor from the given bytes buffer.
293 ///
294 /// The compressor will have a default limit equal to the buffer’s current
295 /// capacity and a page size of 0.
296 pub fn from_buf(buf: BytesMut) -> Self {
297 Compressor {
298 start: buf.len(),
299 limit: buf.capacity(),
300 page_size: 0,
301 buf,
302 map: None }
303 }
304
305 /// Creates a new compressor with a default capacity and limit.
306 ///
307 /// The compressor will be created atop a new buffer which will use its
308 /// default capacity. This is the largest capacity it can use without
309 /// having to allocate. The compressor will start out with a limit equal
310 /// to this capacity and a page size of 0.
311 pub fn new() -> Self {
312 Self::from_buf(BytesMut::new())
313 }
314
315 /// Creates a new compressor with the given capacity.
316 ///
317 /// The compressor will be created atop a new buffer with at least the
318 /// given capacity. The compressor’s initial limit will be the actual
319 /// capacity of the buffer which may be larger than `capacity`. The
320 /// initial page size will be 0.
321 pub fn with_capacity(capacity: usize) -> Self {
322 Self::from_buf(BytesMut::with_capacity(capacity))
323 }
324
325 /// Enable name compression.
326 ///
327 /// By default, a compressor will not actually compress domain names,
328 /// but rather append them like any other data. Instead, compression
329 /// needs to be enable once via this method.
330 pub fn enable_compression(&mut self) {
331 if self.map.is_none() {
332 self.map = Some(HashMap::new())
333 }
334 }
335
336 /// Sets the size limit for the compressor.
337 ///
338 /// This limit only regards the part of the underlying buffer that is
339 /// being built by the compressor. That is, if the compressor was created
340 /// on top of a buffer that already contained data, the buffer will never
341 /// exceed that amount of data plus `limit`.
342 ///
343 /// If you try to set the limit to a value smaller than what has already
344 /// been added so far, the limit will silently be increased to that
345 /// amount.
346 ///
347 /// A new compressor starts out with a size limit equal to the
348 /// remaining capacity of the buffer it is being created with.
349 pub fn set_limit(&mut self, limit: usize) {
350 let limit = limit + self.start;
351 self.limit = ::std::cmp::max(limit, self.buf.len())
352 }
353
354 /// Sets the number of bytes by which the buffer should be grown.
355 ///
356 /// Each time the buffer runs out of capacity and is still below its
357 /// size limit, it will be grown by `page_size` bytes. This may result in
358 /// a buffer with more capacity than the limit.
359 ///
360 /// If `page_size` is set to 0, the buffer will be expanded only once to
361 /// match the size limit.
362 ///
363 /// A new compressor starts out with this specia page size of 0.
364 pub fn set_page_size(&mut self, page_size: usize) {
365 self.page_size = page_size
366 }
367
368 /// Trades in the compressor for its underlying bytes buffer.
369 pub fn unwrap(self) -> BytesMut {
370 self.buf
371 }
372
373 /// Trades in the compressor for the frozen underlying buffer.
374 pub fn freeze(self) -> Bytes {
375 self.buf.freeze()
376 }
377
378 /// Returns a reference to the bytes that have been assembled so far.
379 ///
380 /// This differs from [`as_slice`](#method.as_slice) if the compressor
381 /// was created atop an existing buffer in that the slice does not
382 /// contain the data that was in the buffer before.
383 pub fn so_far(&self) -> &[u8] {
384 &self.buf.as_ref()[self.start..]
385 }
386
387 /// Returns a mutable reference to the data assembled so far.
388 ///
389 /// This differs from [`as_slice_mut`](#method.as_slice_mut) if the
390 /// compressor was created atop an existing buffer in that the slice
391 /// does not contain the data that was in the buffer before.
392 pub fn so_far_mut(&mut self) -> &mut [u8] {
393 &mut self.buf.as_mut()[self.start..]
394 }
395
396 /// Composes a the given name compressed into the buffer.
397 ///
398 /// If compression hasn’t been enable yet via
399 /// [`enable_compression`](#method.enable_compression), the name will be
400 /// appended without compression. It will also not be remembered as a
401 /// compression target for later names.
402 pub fn compress_name<N: ToDname>(&mut self, name: &N)
403 -> Result<(), ShortBuf> {
404 let mut name = name.to_name();
405 while !name.is_root() {
406 if let Some(pos) = self.get_pos(&name) {
407 return self.compose_compress_target(pos)
408 }
409 let pos = {
410 let first = name.first();
411 let pos = self.buf.len() - self.start;
412 self.compose(first)?;
413 pos
414 };
415 self.add_name(&name, pos);
416 name.parent();
417 }
418 self.compose(Label::root())
419 }
420
421 /// Appends a compression label pointing to position `pos`.
422 fn compose_compress_target(&mut self, pos: u16)
423 -> Result<(), ShortBuf> {
424 if self.buf.remaining_mut() < 2 {
425 return Err(ShortBuf)
426 }
427 (pos | 0xC000).compose(&mut self.buf);
428 Ok(())
429 }
430
431 /// Appends something composable to the end of the buffer.
432 ///
433 /// This method can be used to append something and short circuit via the
434 /// question mark operator if it doesn’t fit. This is most helpful when
435 /// implementing the [`Compress`](trait.Compress.html) trait for a
436 /// composite type.
437 pub fn compose<C>(&mut self, what: &C) -> Result<(), ShortBuf>
438 where C: Compose + ?Sized {
439 if self.remaining_mut() < what.compose_len() {
440 return Err(ShortBuf)
441 }
442 what.compose(self);
443 Ok(())
444 }
445
446 /// Remembers that `name` started at position `pos`.
447 ///
448 /// Doesn’t do that, though, if compression hasn’t been enabled yet.
449 fn add_name(&mut self, name: &Dname, pos: usize) {
450 if let Some(ref mut map) = self.map {
451 if pos > 0x3FFF {
452 // Position exceeds encodable position. Don’t add.
453 return
454 }
455 map.insert(name.clone(), pos as u16);
456 }
457 }
458
459 /// Returns the index of a name if it is known.
460 fn get_pos(&self, name: &Dname) -> Option<u16> {
461 match self.map {
462 Some(ref map) => map.get(name).cloned(),
463 None => None
464 }
465 }
466
467 /// Returns a reference to the complete data of the underlying buffer.
468 ///
469 /// This may be more than the assembled data if the compressor was
470 /// created atop a buffer that already contained data.
471 pub fn as_slice(&self) -> &[u8] {
472 self.buf.as_ref()
473 }
474
475 /// Returns a mutable reference to the data of the underlying buffer.
476 ///
477 /// This may be more than the assembled data if the compressor was
478 /// created atop a buffer that already contained data.
479 pub fn as_slice_mut(&mut self) -> &mut [u8] {
480 self.buf.as_mut()
481 }
482
483 /// Grows the buffer size once.
484 ///
485 /// This may panic if used to grow beyond the limit.
486 fn grow(&mut self) {
487 if self.page_size == 0 {
488 let additional = self.limit.checked_sub(self.buf.capacity())
489 .unwrap();
490 self.buf.reserve(additional)
491 }
492 else {
493 self.buf.reserve(self.page_size)
494 }
495 }
496}
497
498
499//--- Default
500
501impl Default for Compressor {
502 fn default() -> Self {
503 Self::new()
504 }
505}
506
507
508//--- AsRef and AsMut
509
510impl AsRef<BytesMut> for Compressor {
511 fn as_ref(&self) -> &BytesMut {
512 &self.buf
513 }
514}
515
516impl AsMut<BytesMut> for Compressor {
517 fn as_mut(&mut self) -> &mut BytesMut {
518 &mut self.buf
519 }
520}
521
522impl AsRef<[u8]> for Compressor {
523 fn as_ref(&self) -> &[u8] {
524 self.buf.as_ref()
525 }
526}
527
528impl AsMut<[u8]> for Compressor {
529 fn as_mut(&mut self) -> &mut [u8] {
530 self.buf.as_mut()
531 }
532}
533
534
535//--- Deref and DerefMut
536
537impl ops::Deref for Compressor {
538 type Target = BytesMut;
539
540 fn deref(&self) -> &Self::Target {
541 &self.buf
542 }
543}
544
545impl ops::DerefMut for Compressor {
546 fn deref_mut(&mut self) -> &mut Self::Target {
547 &mut self.buf
548 }
549}
550
551
552//--- BufMut
553
554impl BufMut for Compressor {
555 fn remaining_mut(&self) -> usize {
556 self.limit - self.buf.len()
557 }
558
559 unsafe fn advance_mut(&mut self, cnt: usize) {
560 assert!(cnt <= self.remaining_mut());
561 while cnt > self.buf.remaining_mut() {
562 self.grow();
563 }
564 self.buf.advance_mut(cnt)
565 }
566
567 unsafe fn bytes_mut(&mut self) -> &mut [u8] {
568 if self.buf.remaining_mut() == 0 && self.remaining_mut() > 0 {
569 self.grow()
570 }
571 self.buf.bytes_mut()
572 }
573}
574
575
576//============ Testing, One, Two =============================================
577
578#[cfg(test)]
579mod test {
580 use super::*;
581 use bytes::BytesMut;
582
583
584 //-------- Compose impls -------------------------------------------------
585
586 #[test]
587 fn compose_endian() {
588 let mut buf = BytesMut::with_capacity(20);
589 0x1234u16.compose(&mut buf);
590 (-0x1234i16).compose(&mut buf);
591 0x12345678u32.compose(&mut buf);
592 (-0x12345678i32).compose(&mut buf);
593 assert_eq!(buf.as_ref(),
594 b"\x12\x34\xed\xcc\x12\x34\x56\x78\xed\xcb\xa9\x88");
595 }
596
597
598 //-------- Compressor ----------------------------------------------------
599
600 #[test]
601 fn limit() {
602 let mut buf = Compressor::new();
603 buf.set_limit(2);
604 assert_eq!(buf.remaining_mut(), 2);
605 assert!(buf.compose(&0u32).is_err());
606 buf.compose(&0u16).unwrap();
607 assert!(buf.compose(&0u16).is_err());
608
609 buf.set_limit(512); // definitely needs to realloc
610 assert_eq!(buf.remaining_mut(), 510);
611 buf.compose(AsRef::<[u8]>::as_ref(&vec![0u8; 508])).unwrap();
612 assert!(buf.compose(&0u32).is_err());
613 buf.compose(&0u16).unwrap();
614 assert!(buf.compose(&0u16).is_err());
615
616 let mut buf = Compressor::from_buf(buf.unwrap());
617 assert_eq!(buf.so_far().len(), 0);
618 buf.set_limit(512);
619 buf.set_page_size(16);
620 assert_eq!(buf.remaining_mut(), 512);
621 buf.compose(AsRef::<[u8]>::as_ref(&vec![0u8; 510])).unwrap();
622 assert_eq!(buf.remaining_mut(), 2);
623 assert_eq!(buf.so_far().len(), 510);
624 }
625
626 #[test]
627 fn compressed_names() {
628 // Same name again
629 //
630 let mut buf = Compressor::with_capacity(1024);
631 buf.enable_compression();
632 buf.compose(&7u8).unwrap();
633 let name = Dname::from_slice(b"\x03foo\x03bar\x00").unwrap();
634 buf.compress_name(&name).unwrap();
635 buf.compress_name(&name).unwrap();
636 assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\xC0\x01");
637
638 // Prefixed name.
639 //
640 let mut buf = Compressor::with_capacity(1024);
641 buf.enable_compression();
642 buf.compose(&7u8).unwrap();
643 Dname::from_slice(b"\x03foo\x03bar\x00").unwrap()
644 .compress(&mut buf).unwrap();
645 Dname::from_slice(b"\x03baz\x03foo\x03bar\x00").unwrap()
646 .compress(&mut buf).unwrap();
647 assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\x03baz\xC0\x01");
648
649 // Suffixed name.
650 //
651 let mut buf = Compressor::with_capacity(1024);
652 buf.enable_compression();
653 buf.compose(&7u8).unwrap();
654 Dname::from_slice(b"\x03foo\x03bar\x00").unwrap()
655 .compress(&mut buf).unwrap();
656 Dname::from_slice(b"\x03baz\x03bar\x00").unwrap()
657 .compress(&mut buf).unwrap();
658 assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\x03baz\xC0\x05");
659
660 // Don’t compress the root label.
661 //
662 let mut buf = Compressor::with_capacity(1024);
663 buf.enable_compression();
664 buf.compose(&7u8).unwrap();
665 Dname::root().compress(&mut buf).unwrap();
666 Dname::from_slice(b"\x03foo\x00").unwrap()
667 .compress(&mut buf).unwrap();
668 Dname::root().compress(&mut buf).unwrap();
669 assert_eq!(buf.so_far(), b"\x07\x00\x03foo\x00\x00");
670 }
671}