1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! null record type, generally not used except as an internal tool for representing null data
use std::fmt;

#[cfg(feature = "serde-config")]
use serde::{Deserialize, Serialize};

use crate::{
    error::ProtoResult,
    rr::{RData, RecordData, RecordDataDecodable, RecordType},
    serialize::binary::{BinDecoder, BinEncodable, BinEncoder, Restrict},
};

/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035)
///
/// ```text
/// 3.3.10. NULL RDATA format (EXPERIMENTAL)
///
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///     /                  <anything>                   /
///     /                                               /
///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///
/// Anything at all may be in the RDATA field so long as it is 65535 octets
/// or less.
///
/// NULL records cause no additional section processing.  NULL RRs are not
/// allowed in Zone Files.  NULLs are used as placeholders in some
/// experimental extensions of the DNS.
/// ```
#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
#[derive(Default, Debug, PartialEq, Eq, Hash, Clone)]
pub struct NULL {
    anything: Vec<u8>,
}

impl NULL {
    /// Construct a new NULL RData
    pub const fn new() -> Self {
        Self {
            anything: Vec::new(),
        }
    }

    /// Constructs a new NULL RData with the associated data
    pub fn with(anything: Vec<u8>) -> Self {
        // FIXME: we don't want empty data for NULL's, should be Option in the Record
        debug_assert!(!anything.is_empty());

        Self { anything }
    }

    /// Returns the buffer stored in the NULL
    pub fn anything(&self) -> &[u8] {
        &self.anything
    }
}

impl BinEncodable for NULL {
    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
        for b in self.anything() {
            encoder.emit(*b)?;
        }

        Ok(())
    }
}

impl<'r> RecordDataDecodable<'r> for NULL {
    fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> ProtoResult<Self> {
        let rdata_length = length.map(|u| u as usize).unverified(/*any u16 is valid*/);
        if rdata_length > 0 {
            let anything = decoder.read_vec(rdata_length)?.unverified(/*any byte array is good*/);
            Ok(Self::with(anything))
        } else {
            Ok(Self::new())
        }
    }
}

impl RecordData for NULL {
    fn try_from_rdata(data: RData) -> Result<Self, RData> {
        match data {
            RData::NULL(csync) => Ok(csync),
            _ => Err(data),
        }
    }

    fn try_borrow(data: &RData) -> Option<&Self> {
        match data {
            RData::NULL(csync) => Some(csync),
            _ => None,
        }
    }

    fn record_type(&self) -> RecordType {
        RecordType::NULL
    }

    fn into_rdata(self) -> RData {
        RData::NULL(self)
    }
}

impl fmt::Display for NULL {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        f.write_str(&data_encoding::BASE64.encode(&self.anything))
    }
}

#[cfg(test)]
mod tests {
    #![allow(clippy::dbg_macro, clippy::print_stdout)]

    use super::*;

    #[test]
    fn test() {
        let rdata = NULL::with(vec![0, 1, 2, 3, 4, 5, 6, 7]);

        let mut bytes = Vec::new();
        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
        assert!(rdata.emit(&mut encoder).is_ok());
        let bytes = encoder.into_bytes();

        println!("bytes: {bytes:?}");

        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
        let restrict = Restrict::new(bytes.len() as u16);
        let read_rdata = NULL::read_data(&mut decoder, restrict).expect("Decoding error");
        assert_eq!(rdata, read_rdata);
    }
}