hickory_proto/rr/rdata/
null.rs

1// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! null record type, generally not used except as an internal tool for representing null data
9use alloc::vec::Vec;
10use core::fmt;
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15use crate::{
16    error::ProtoResult,
17    rr::{RData, RecordData, RecordDataDecodable, RecordType},
18    serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
19};
20
21/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
22///
23/// ```text
24/// 3.3.10. NULL RDATA format (EXPERIMENTAL)
25///
26///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
27///     /                  <anything>                   /
28///     /                                               /
29///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
30///
31/// Anything at all may be in the RDATA field so long as it is 65535 octets
32/// or less.
33///
34/// NULL records cause no additional section processing.  NULL RRs are not
35/// allowed in Zone Files.  NULLs are used as placeholders in some
36/// experimental extensions of the DNS.
37/// ```
38#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
39#[derive(Default, Debug, PartialEq, Eq, Hash, Clone)]
40pub struct NULL {
41    anything: Vec<u8>,
42}
43
44impl NULL {
45    /// Construct a new NULL RData
46    pub const fn new() -> Self {
47        Self {
48            anything: Vec::new(),
49        }
50    }
51
52    /// Constructs a new NULL RData with the associated data
53    pub fn with(anything: Vec<u8>) -> Self {
54        // FIXME: we don't want empty data for NULL's, should be Option in the Record
55        debug_assert!(!anything.is_empty());
56
57        Self { anything }
58    }
59
60    /// Returns the buffer stored in the NULL
61    pub fn anything(&self) -> &[u8] {
62        &self.anything
63    }
64}
65
66impl BinEncodable for NULL {
67    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
68        for b in self.anything() {
69            encoder.emit(*b)?;
70        }
71
72        Ok(())
73    }
74}
75
76impl<'r> RecordDataDecodable<'r> for NULL {
77    fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> ProtoResult<Self> {
78        let rdata_length = length.map(|u| u as usize).unverified(/*any u16 is valid*/);
79        if rdata_length > 0 {
80            let anything = decoder.read_vec(rdata_length)?.unverified(/*any byte array is good*/);
81            Ok(Self::with(anything))
82        } else {
83            Ok(Self::new())
84        }
85    }
86}
87
88impl RecordData for NULL {
89    fn try_from_rdata(data: RData) -> Result<Self, RData> {
90        match data {
91            RData::NULL(csync) => Ok(csync),
92            _ => Err(data),
93        }
94    }
95
96    fn try_borrow(data: &RData) -> Option<&Self> {
97        match data {
98            RData::NULL(csync) => Some(csync),
99            _ => None,
100        }
101    }
102
103    fn record_type(&self) -> RecordType {
104        RecordType::NULL
105    }
106
107    fn into_rdata(self) -> RData {
108        RData::NULL(self)
109    }
110}
111
112impl fmt::Display for NULL {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
114        f.write_str(&data_encoding::BASE64.encode(&self.anything))
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    #![allow(clippy::dbg_macro, clippy::print_stdout)]
121
122    #[cfg(feature = "std")]
123    use std::println;
124
125    use super::*;
126
127    #[test]
128    fn test() {
129        let rdata = NULL::with(vec![0, 1, 2, 3, 4, 5, 6, 7]);
130
131        let mut bytes = Vec::new();
132        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
133        assert!(rdata.emit(&mut encoder).is_ok());
134        let bytes = encoder.into_bytes();
135
136        #[cfg(feature = "std")]
137        println!("bytes: {bytes:?}");
138
139        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
140        let restrict = Restrict::new(bytes.len() as u16);
141        let read_rdata = NULL::read_data(&mut decoder, restrict).expect("Decoding error");
142        assert_eq!(rdata, read_rdata);
143    }
144}