simple_dns/dns/rdata/
zonemd.rs

1use crate::{bytes_buffer::BytesBuffer, dns::WireFormat};
2use std::borrow::Cow;
3
4use super::RR;
5
6/// A ZoneMD record see [rfc8976](https://www.rfc-editor.org/rfc/rfc8976.html)
7#[derive(Debug, PartialEq, Eq, Hash, Clone)]
8pub struct ZONEMD<'a> {
9    /// The serial number of the zone's SOA record
10    pub serial: u32,
11    /// The scheme in which data is hashed
12    pub scheme: u8,
13    /// The hashing algorithm ID to use (see [rfc8976](https://www.rfc-editor.org/rfc/rfc8976.html#name-the-hash-algorithm-field))
14    pub algorithm: u8,
15    /// The output data of the hash algorithm.
16    pub digest: Cow<'a, [u8]>,
17}
18
19impl RR for ZONEMD<'_> {
20    const TYPE_CODE: u16 = 63;
21}
22
23impl<'a> WireFormat<'a> for ZONEMD<'a> {
24    const MINIMUM_LEN: usize = 6;
25
26    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
27    where
28        Self: Sized,
29    {
30        let serial = data.get_u32()?;
31        let scheme = data.get_u8()?;
32        let algorithm = data.get_u8()?;
33        let digest = Cow::Borrowed(data.get_remaining());
34
35        Ok(Self {
36            serial,
37            scheme,
38            algorithm,
39            digest,
40        })
41    }
42
43    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
44        out.write_all(&self.serial.to_be_bytes())?;
45        out.write_all(&[self.scheme])?;
46        out.write_all(&[self.algorithm])?;
47        out.write_all(&self.digest)?;
48
49        Ok(())
50    }
51
52    fn len(&self) -> usize {
53        self.digest.len() + Self::MINIMUM_LEN
54    }
55}
56
57impl ZONEMD<'_> {
58    /// Transforms the inner data into its owned type
59    pub fn into_owned<'b>(self) -> ZONEMD<'b> {
60        ZONEMD {
61            scheme: self.scheme,
62            serial: self.serial,
63            algorithm: self.algorithm,
64            digest: self.digest.into_owned().into(),
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::{
72        rdata::{RData, ZONEMD},
73        ResourceRecord,
74    };
75
76    use super::*;
77
78    #[test]
79    fn parse_and_write_srv() {
80        let zonemd = ZONEMD {
81            serial: 1,
82            scheme: 2,
83            algorithm: 3,
84            digest: Cow::Borrowed(&[4, 5, 6]),
85        };
86
87        let mut bytes = Vec::new();
88        assert!(zonemd.write_to(&mut bytes).is_ok());
89
90        let zonemd = ZONEMD::parse(&mut bytes[..].into());
91        assert!(zonemd.is_ok());
92        let zonemd = zonemd.unwrap();
93
94        assert_eq!(zonemd.serial, 1);
95        assert_eq!(zonemd.scheme, 2);
96        assert_eq!(zonemd.algorithm, 3);
97        assert_eq!(*zonemd.digest, *b"\x04\x05\x06");
98    }
99
100    #[test]
101    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
102        let sample_file = std::fs::read("samples/zonefile/ZONEMD.sample")?;
103
104        let sample_rdata = match ResourceRecord::parse(&mut sample_file[..].into())?.rdata {
105            RData::ZONEMD(rdata) => rdata,
106            _ => unreachable!(),
107        };
108
109        assert_eq!(sample_rdata.serial, 2018031500);
110        assert_eq!(sample_rdata.scheme, 1);
111        assert_eq!(sample_rdata.algorithm, 1);
112        assert_eq!(*sample_rdata.digest, *b"\xFE\xBE\x3D\x4C\xE2\xEC\x2F\xFA\x4B\xA9\x9D\x46\xCD\x69\xD6\xD2\x97\x11\xE5\x52\x17\x05\x7B\xEE\x7E\xB1\xA7\xB6\x41\xA4\x7B\xA7\xFE\xD2\xDD\x5B\x97\xAE\x49\x9F\xAF\xA4\xF2\x2C\x6B\xD6\x47\xDE");
113
114        Ok(())
115    }
116}