dns_message_parser/rr/
rfc_8659.rs

1use super::Class;
2use crate::DomainName;
3use hex::encode;
4use std::convert::{AsRef, TryFrom};
5use std::fmt::{Display, Formatter, Result as FmtResult};
6use thiserror::Error;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Error)]
9pub enum TagError {
10    #[error("Tag is empty")]
11    Empty,
12    #[error("Tag contains illegal character: {0}")]
13    IllegalChar(char),
14}
15
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17pub struct Tag(String);
18
19impl TryFrom<String> for Tag {
20    type Error = TagError;
21
22    fn try_from(mut tag: String) -> Result<Self, Self::Error> {
23        if tag.is_empty() {
24            return Err(TagError::Empty);
25        }
26
27        for c in tag.chars() {
28            if !c.is_ascii_alphanumeric() {
29                return Err(TagError::IllegalChar(c));
30            }
31        }
32
33        tag.make_ascii_lowercase();
34        Ok(Tag(tag))
35    }
36}
37
38impl AsRef<str> for Tag {
39    fn as_ref(&self) -> &str {
40        &self.0
41    }
42}
43
44impl Display for Tag {
45    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
46        write!(f, "{}", self.0)
47    }
48}
49
50/// The [certification authority authorization] resource record type.
51///
52/// [certification authority authorization]: https://tools.ietf.org/html/rfc8659#section-4
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub struct CAA {
55    pub domain_name: DomainName,
56    pub ttl: u32,
57    pub class: Class,
58    pub flags: u8,
59    pub tag: Tag,
60    pub value: Vec<u8>,
61}
62
63impl_to_type!(CAA);
64
65impl Display for CAA {
66    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
67        write!(
68            f,
69            "{} {} {} CAA {} {} {}",
70            self.domain_name,
71            self.ttl,
72            self.class,
73            self.flags,
74            self.tag,
75            encode(&self.value)
76        )
77    }
78}