trust_dns_proto/rr/rdata/
hinfo.rs

1// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! HINFO record for storing host information
9
10use std::fmt;
11
12#[cfg(feature = "serde-config")]
13use serde::{Deserialize, Serialize};
14
15use crate::error::*;
16use crate::serialize::binary::*;
17
18/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987][rfc1035]
19///
20/// ```text
21/// 3.3.2. HINFO RDATA format
22///
23///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
24///     /                      CPU                      /
25///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
26///     /                       OS                      /
27///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
28///
29/// where:
30///
31/// CPU             A <character-string> which specifies the CPU type.
32///
33/// OS              A <character-string> which specifies the operating
34///                 system type.
35///
36/// Standard values for CPU and OS can be found in [RFC-1010].
37///
38/// HINFO records are used to acquire general information about a host.  The
39/// main use is for protocols such as FTP that can use special procedures
40/// when talking between machines or operating systems of the same type.
41/// ```
42///
43/// [rfc1035]: https://tools.ietf.org/html/rfc1035
44#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
45#[derive(Debug, PartialEq, Eq, Hash, Clone)]
46pub struct HINFO {
47    cpu: Box<[u8]>,
48    os: Box<[u8]>,
49}
50
51impl HINFO {
52    /// Creates a new HINFO record data.
53    ///
54    /// # Arguments
55    ///
56    /// * `cpu` - A <character-string> which specifies the CPU type.
57    /// * `os` - A <character-string> which specifies the operating system type.
58    ///
59    /// # Return value
60    ///
61    /// The new HINFO record data.
62    pub fn new(cpu: String, os: String) -> Self {
63        Self {
64            cpu: cpu.into_bytes().into_boxed_slice(),
65            os: os.into_bytes().into_boxed_slice(),
66        }
67    }
68
69    /// Creates a new HINFO record data from bytes.
70    /// Allows creating binary record data.
71    ///
72    /// # Arguments
73    ///
74    /// * `cpu` - A <character-string> which specifies the CPU type.
75    /// * `os` - A <character-string> which specifies the operating system type.
76    ///
77    /// # Return value
78    ///
79    /// The new HINFO record data.
80    pub fn from_bytes(cpu: Box<[u8]>, os: Box<[u8]>) -> Self {
81        Self { cpu, os }
82    }
83
84    /// A <character-string> which specifies the CPU type.
85    pub fn cpu(&self) -> &[u8] {
86        &self.cpu
87    }
88
89    /// A <character-string> which specifies the operating system type.
90    pub fn os(&self) -> &[u8] {
91        &self.os
92    }
93}
94
95/// Read the RData from the given Decoder
96pub fn read(decoder: &mut BinDecoder<'_>) -> ProtoResult<HINFO> {
97    let cpu = decoder.read_character_data()?
98        .unverified(/*any data should be validate in HINFO CPU usage*/)
99        .to_vec()
100        .into_boxed_slice();
101    let os = decoder.read_character_data()?
102        .unverified(/*any data should be validate in HINFO OS usage*/)
103        .to_vec()
104        .into_boxed_slice();
105
106    Ok(HINFO { cpu, os })
107}
108
109/// Write the RData from the given Decoder
110pub fn emit(encoder: &mut BinEncoder<'_>, hinfo: &HINFO) -> ProtoResult<()> {
111    encoder.emit_character_data(&hinfo.cpu)?;
112    encoder.emit_character_data(&hinfo.os)?;
113
114    Ok(())
115}
116
117/// [RFC 1033](https://tools.ietf.org/html/rfc1033), DOMAIN OPERATIONS GUIDE, November 1987
118///
119/// ```text
120/// HINFO (Host Info)
121///
122///            <host>   [<ttl>] [<class>]   HINFO   <hardware>   <software>
123///
124///    The HINFO record gives information about a particular host.  The data
125///    is two strings separated by whitespace.  The first string is a
126///    hardware description and the second is software.  The hardware is
127///    usually a manufacturer name followed by a dash and model designation.
128///    The software string is usually the name of the operating system.
129///
130///    Official HINFO types can be found in the latest Assigned Numbers RFC,
131///    the latest of which is RFC-1010.  The Hardware type is called the
132///    Machine name and the Software type is called the System name.
133///
134///    Some sample HINFO records:
135///
136///            SRI-NIC.ARPA.           HINFO   DEC-2060 TOPS20
137///            UCBARPA.Berkeley.EDU.   HINFO   VAX-11/780 UNIX
138/// ```
139impl fmt::Display for HINFO {
140    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
141        write!(
142            f,
143            "{cpu} {os}",
144            cpu = &String::from_utf8_lossy(&self.cpu),
145            os = &String::from_utf8_lossy(&self.os)
146        )?;
147        Ok(())
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    #![allow(clippy::dbg_macro, clippy::print_stdout)]
154
155    use super::*;
156
157    #[test]
158    fn test() {
159        let rdata = HINFO::new("cpu".to_string(), "os".to_string());
160
161        let mut bytes = Vec::new();
162        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
163        assert!(emit(&mut encoder, &rdata).is_ok());
164        let bytes = encoder.into_bytes();
165
166        println!("bytes: {:?}", bytes);
167
168        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
169        let read_rdata = read(&mut decoder).expect("Decoding error");
170        assert_eq!(rdata, read_rdata);
171    }
172
173    #[test]
174    fn test_binary() {
175        let bin_data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
176        let rdata = HINFO::from_bytes(
177            b"cpu".to_vec().into_boxed_slice(),
178            bin_data.into_boxed_slice(),
179        );
180
181        let mut bytes = Vec::new();
182        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
183        assert!(emit(&mut encoder, &rdata).is_ok());
184        let bytes = encoder.into_bytes();
185
186        println!("bytes: {:?}", bytes);
187
188        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
189        let read_rdata = read(&mut decoder).expect("Decoding error");
190        assert_eq!(rdata, read_rdata);
191    }
192}