blob: 1c689d104a3bb41dfdc8c48876eb9a192667d2d8 [file] [log] [blame]
// Copyright 2015-2017 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.
//! class of DNS operations, in general always IN for internet
use std::cmp::Ordering;
use std::convert::From;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
use crate::error::*;
use crate::serialize::binary::*;
/// The DNS Record class
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
#[allow(dead_code)]
pub enum DNSClass {
/// Internet
IN,
/// Chaos
CH,
/// Hesiod
HS,
/// QCLASS NONE
NONE,
/// QCLASS * (ANY)
ANY,
/// Special class for OPT Version, it was overloaded for EDNS - RFC 6891
/// From the RFC: `Values lower than 512 MUST be treated as equal to 512`
OPT(u16),
}
impl FromStr for DNSClass {
type Err = ProtoError;
/// Convert from `&str` to `DNSClass`
///
/// ```
/// use std::str::FromStr;
/// use trust_dns_proto::rr::dns_class::DNSClass;
///
/// let var: DNSClass = DNSClass::from_str("IN").unwrap();
/// assert_eq!(DNSClass::IN, var);
/// ```
fn from_str(str: &str) -> ProtoResult<Self> {
match str {
"IN" => Ok(DNSClass::IN),
"CH" => Ok(DNSClass::CH),
"HS" => Ok(DNSClass::HS),
"NONE" => Ok(DNSClass::NONE),
"ANY" | "*" => Ok(DNSClass::ANY),
_ => Err(ProtoErrorKind::UnknownDnsClassStr(str.to_string()).into()),
}
}
}
impl DNSClass {
/// Convert from `u16` to `DNSClass`
///
/// ```
/// use trust_dns_proto::rr::dns_class::DNSClass;
///
/// let var = DNSClass::from_u16(1).unwrap();
/// assert_eq!(DNSClass::IN, var);
/// ```
pub fn from_u16(value: u16) -> ProtoResult<Self> {
match value {
1 => Ok(DNSClass::IN),
3 => Ok(DNSClass::CH),
4 => Ok(DNSClass::HS),
254 => Ok(DNSClass::NONE),
255 => Ok(DNSClass::ANY),
_ => Err(ProtoErrorKind::UnknownDnsClassValue(value).into()),
}
}
/// Return the OPT version from value
pub fn for_opt(value: u16) -> Self {
// From RFC 6891: `Values lower than 512 MUST be treated as equal to 512`
let value = value.max(512);
DNSClass::OPT(value)
}
}
impl BinEncodable for DNSClass {
fn emit(&self, encoder: &mut BinEncoder) -> ProtoResult<()> {
encoder.emit_u16((*self).into())
}
}
impl<'r> BinDecodable<'r> for DNSClass {
fn read(decoder: &mut BinDecoder) -> ProtoResult<Self> {
Self::from_u16(
decoder.read_u16()?.unverified(/*DNSClass is verified as safe in processing this*/),
)
}
}
// TODO make these a macro or annotation
/// Convert from `DNSClass` to `&str`
///
/// ```
/// use trust_dns_proto::rr::dns_class::DNSClass;
///
/// let var: &'static str = DNSClass::IN.into();
/// assert_eq!("IN", var);
/// ```
impl From<DNSClass> for &'static str {
fn from(rt: DNSClass) -> &'static str {
match rt {
DNSClass::IN => "IN",
DNSClass::CH => "CH",
DNSClass::HS => "HS",
DNSClass::NONE => "NONE",
DNSClass::ANY => "ANY",
DNSClass::OPT(_) => "OPT",
}
}
}
/// Convert from `DNSClass` to `u16`
///
/// ```
/// use trust_dns_proto::rr::dns_class::DNSClass;
///
/// let var: u16 = DNSClass::IN.into();
/// assert_eq!(1, var);
/// ```
impl From<DNSClass> for u16 {
fn from(rt: DNSClass) -> Self {
match rt {
DNSClass::IN => 1,
DNSClass::CH => 3,
DNSClass::HS => 4,
DNSClass::NONE => 254,
DNSClass::ANY => 255,
// see https://tools.ietf.org/html/rfc6891#section-6.1.2
DNSClass::OPT(max_payload_len) => max_payload_len.max(512),
}
}
}
impl PartialOrd<DNSClass> for DNSClass {
fn partial_cmp(&self, other: &DNSClass) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for DNSClass {
fn cmp(&self, other: &Self) -> Ordering {
u16::from(*self).cmp(&u16::from(*other))
}
}
impl Display for DNSClass {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
f.write_str(Into::<&str>::into(*self))
}
}
#[test]
fn test_order() {
let ordered = vec![
DNSClass::IN,
DNSClass::CH,
DNSClass::HS,
DNSClass::NONE,
DNSClass::ANY,
];
let mut unordered = vec![
DNSClass::NONE,
DNSClass::HS,
DNSClass::CH,
DNSClass::IN,
DNSClass::ANY,
];
unordered.sort();
assert_eq!(unordered, ordered);
}