simple_dns/dns/rdata/
hinfo.rs

1use std::collections::HashMap;
2
3use crate::dns::{name::Label, CharacterString, WireFormat};
4
5use super::RR;
6
7/// HINFO records are used to acquire general information about a host.  
8/// The main use is for protocols such as FTP that can use special procedures
9/// when talking between machines or operating systems of the same type.
10#[derive(Debug, PartialEq, Eq, Hash, Clone)]
11pub struct HINFO<'a> {
12    /// A [CharacterString](`CharacterString`) which specifies the CPU type.
13    pub cpu: CharacterString<'a>,
14    /// A [CharacterString](`CharacterString`) which specifies the operating system type.
15    pub os: CharacterString<'a>,
16}
17
18impl<'a> RR for HINFO<'a> {
19    const TYPE_CODE: u16 = 13;
20}
21
22impl<'a> HINFO<'a> {
23    /// Transforms the inner data into its owned type
24    pub fn into_owned<'b>(self) -> HINFO<'b> {
25        HINFO {
26            cpu: self.cpu.into_owned(),
27            os: self.os.into_owned(),
28        }
29    }
30}
31
32impl<'a> WireFormat<'a> for HINFO<'a> {
33    fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
34    where
35        Self: Sized,
36    {
37        let cpu = CharacterString::parse(data, position)?;
38        let os = CharacterString::parse(data, position)?;
39
40        Ok(Self { cpu, os })
41    }
42
43    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
44        self.cpu.write_to(out)?;
45        self.os.write_to(out)
46    }
47
48    fn write_compressed_to<T: std::io::Write + std::io::Seek>(
49        &'a self,
50        out: &mut T,
51        name_refs: &mut HashMap<&'a [Label<'a>], usize>,
52    ) -> crate::Result<()> {
53        self.cpu.write_compressed_to(out, name_refs)?;
54        self.os.write_compressed_to(out, name_refs)
55    }
56
57    fn len(&self) -> usize {
58        self.cpu.len() + self.os.len()
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use crate::{rdata::RData, ResourceRecord};
65
66    use super::*;
67
68    #[test]
69    fn parse_and_write_hinfo() {
70        let hinfo = HINFO {
71            cpu: CharacterString::new(b"\"some cpu").unwrap(),
72            os: CharacterString::new(b"\"some os").unwrap(),
73        };
74
75        let mut data = Vec::new();
76        assert!(hinfo.write_to(&mut data).is_ok());
77
78        let hinfo = HINFO::parse(&data, &mut 0);
79        assert!(hinfo.is_ok());
80        let hinfo = hinfo.unwrap();
81
82        assert_eq!(data.len(), hinfo.len());
83        assert_eq!("\"some cpu", hinfo.cpu.to_string());
84        assert_eq!("\"some os", hinfo.os.to_string());
85    }
86
87    #[test]
88    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
89        let sample_file = std::fs::read("samples/zonefile/HINFO.sample")?;
90
91        let sample_rdata = match ResourceRecord::parse(&sample_file, &mut 0)?.rdata {
92            RData::HINFO(rdata) => rdata,
93            _ => unreachable!(),
94        };
95
96        assert_eq!(sample_rdata.cpu, "Generic PC clone".try_into()?);
97        assert_eq!(sample_rdata.os, "NetBSD-1.4".try_into()?);
98        Ok(())
99    }
100}