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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
// 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.
//! HINFO record for storing host information
use std::fmt;
#[cfg(feature = "serde-config")]
use serde::{Deserialize, Serialize};
use crate::{
error::*,
rr::{RData, RecordData, RecordType},
serialize::binary::*,
};
/// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987][rfc1035]
///
/// ```text
/// 3.3.2. HINFO RDATA format
///
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// / CPU /
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/// / OS /
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
///
/// where:
///
/// CPU A <character-string> which specifies the CPU type.
///
/// OS A <character-string> which specifies the operating
/// system type.
///
/// Standard values for CPU and OS can be found in [RFC-1010].
///
/// HINFO records are used to acquire general information about a host. The
/// main use is for protocols such as FTP that can use special procedures
/// when talking between machines or operating systems of the same type.
/// ```
///
/// [rfc1035]: https://tools.ietf.org/html/rfc1035
#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct HINFO {
cpu: Box<[u8]>,
os: Box<[u8]>,
}
impl HINFO {
/// Creates a new HINFO record data.
///
/// # Arguments
///
/// * `cpu` - A <character-string> which specifies the CPU type.
/// * `os` - A <character-string> which specifies the operating system type.
///
/// # Return value
///
/// The new HINFO record data.
pub fn new(cpu: String, os: String) -> Self {
Self {
cpu: cpu.into_bytes().into_boxed_slice(),
os: os.into_bytes().into_boxed_slice(),
}
}
/// Creates a new HINFO record data from bytes.
/// Allows creating binary record data.
///
/// # Arguments
///
/// * `cpu` - A <character-string> which specifies the CPU type.
/// * `os` - A <character-string> which specifies the operating system type.
///
/// # Return value
///
/// The new HINFO record data.
pub fn from_bytes(cpu: Box<[u8]>, os: Box<[u8]>) -> Self {
Self { cpu, os }
}
/// A <character-string> which specifies the CPU type.
pub fn cpu(&self) -> &[u8] {
&self.cpu
}
/// A <character-string> which specifies the operating system type.
pub fn os(&self) -> &[u8] {
&self.os
}
}
impl BinEncodable for HINFO {
fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
encoder.emit_character_data(&self.cpu)?;
encoder.emit_character_data(&self.os)?;
Ok(())
}
}
impl<'r> BinDecodable<'r> for HINFO {
fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
let cpu = decoder.read_character_data()?
.unverified(/*any data should be validate in HINFO CPU usage*/)
.to_vec()
.into_boxed_slice();
let os = decoder.read_character_data()?
.unverified(/*any data should be validate in HINFO OS usage*/)
.to_vec()
.into_boxed_slice();
Ok(Self { cpu, os })
}
}
impl RecordData for HINFO {
fn try_from_rdata(data: RData) -> Result<Self, RData> {
match data {
RData::HINFO(csync) => Ok(csync),
_ => Err(data),
}
}
fn try_borrow(data: &RData) -> Option<&Self> {
match data {
RData::HINFO(csync) => Some(csync),
_ => None,
}
}
fn record_type(&self) -> RecordType {
RecordType::HINFO
}
fn into_rdata(self) -> RData {
RData::HINFO(self)
}
}
/// [RFC 1033](https://tools.ietf.org/html/rfc1033), DOMAIN OPERATIONS GUIDE, November 1987
///
/// ```text
/// HINFO (Host Info)
///
/// <host> [<ttl>] [<class>] HINFO <hardware> <software>
///
/// The HINFO record gives information about a particular host. The data
/// is two strings separated by whitespace. The first string is a
/// hardware description and the second is software. The hardware is
/// usually a manufacturer name followed by a dash and model designation.
/// The software string is usually the name of the operating system.
///
/// Official HINFO types can be found in the latest Assigned Numbers RFC,
/// the latest of which is RFC-1010. The Hardware type is called the
/// Machine name and the Software type is called the System name.
///
/// Some sample HINFO records:
///
/// SRI-NIC.ARPA. HINFO DEC-2060 TOPS20
/// UCBARPA.Berkeley.EDU. HINFO VAX-11/780 UNIX
/// ```
impl fmt::Display for HINFO {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(
f,
"{cpu} {os}",
cpu = &String::from_utf8_lossy(&self.cpu),
os = &String::from_utf8_lossy(&self.os)
)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::dbg_macro, clippy::print_stdout)]
use super::*;
#[test]
fn test() {
let rdata = HINFO::new("cpu".to_string(), "os".to_string());
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 read_rdata = HINFO::read(&mut decoder).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
#[test]
fn test_binary() {
let bin_data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
let rdata = HINFO::from_bytes(
b"cpu".to_vec().into_boxed_slice(),
bin_data.into_boxed_slice(),
);
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 read_rdata = HINFO::read(&mut decoder).expect("Decoding error");
assert_eq!(rdata, read_rdata);
}
}