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);
}
}