ddns/core/parser/
question.rs1use std::io;
2
3use nom::number::streaming::be_u16;
4
5use super::name::{Name, be_name};
6
7#[derive(Debug, Clone)]
21pub struct Question {
22 pub(crate) name: Name,
23 pub(crate) prefer_unicast: bool,
24 pub(crate) qtype: QueryType,
25 pub(crate) qclass: QueryClass,
26}
27
28impl Question {
29 pub fn name(&self) -> &Name {
30 &self.name
31 }
32
33 pub fn prefer_unicast(&self) -> bool {
34 self.prefer_unicast
35 }
36
37 pub fn qtype(&self) -> QueryType {
38 self.qtype
39 }
40
41 pub fn qclass(&self) -> QueryClass {
42 self.qclass
43 }
44}
45
46#[derive(Debug, PartialEq, Eq, Clone, Copy)]
47pub enum QueryType {
48 A,
50 #[allow(clippy::upper_case_acronyms)]
52 AAAA,
53 Cname,
55 Txt,
57 Srv,
59 Ptr,
61 E,
64 E6,
66 EE,
68 EE6,
70}
71
72impl TryFrom<u16> for QueryType {
73 type Error = io::Error;
74
75 fn try_from(value: u16) -> Result<Self, Self::Error> {
76 let query = match value {
77 1 => Self::A,
78 28 => Self::AAAA,
79 5 => Self::Cname,
80 16 => Self::Txt,
81 33 => Self::Srv,
82 12 => Self::Ptr,
83 266 => Self::E,
84 267 => Self::E6,
85 268 => Self::EE,
86 269 => Self::EE6,
87 _ => {
88 return Err(io::Error::new(
89 io::ErrorKind::InvalidInput,
90 format!("Unknown query type {value}"),
91 ));
92 }
93 };
94 Ok(query)
95 }
96}
97
98impl From<QueryType> for u16 {
99 fn from(value: QueryType) -> Self {
100 match value {
101 QueryType::A => 1,
102 QueryType::AAAA => 28,
103 QueryType::Cname => 5,
104 QueryType::Txt => 16,
105 QueryType::Srv => 33,
106 QueryType::Ptr => 12,
107 QueryType::E => 266,
108 QueryType::E6 => 267,
109 QueryType::EE => 268,
110 QueryType::EE6 => 269,
111 }
112 }
113}
114
115#[derive(Debug, PartialEq, Eq, Clone, Copy)]
117pub enum QueryClass {
118 IN = 1,
120 CS = 2,
123 CH = 3,
125 HS = 4,
127 Any = 255,
129}
130
131impl From<QueryClass> for u16 {
132 fn from(query: QueryClass) -> u16 {
133 match query {
134 QueryClass::IN => 1,
135 QueryClass::CS => 2,
136 QueryClass::CH => 3,
137 QueryClass::HS => 4,
138 QueryClass::Any => 255,
139 }
140 }
141}
142
143impl TryFrom<u16> for QueryClass {
144 type Error = io::Error;
145
146 fn try_from(value: u16) -> Result<Self, Self::Error> {
147 let query = match value {
148 1 => Self::IN,
149 2 => Self::CS,
150 3 => Self::CH,
151 4 => Self::HS,
152 255 => Self::Any,
153 _ => {
154 return Err(io::Error::new(
155 io::ErrorKind::InvalidInput,
156 format!("Unknown query class {value}"),
157 ));
158 }
159 };
160 Ok(query)
161 }
162}
163
164pub fn be_question<'a>(input: &'a [u8], origin: &'a [u8]) -> nom::IResult<&'a [u8], Question> {
165 let (remain, name) = be_name(input, origin)?;
166 let (remain, qtype) = be_u16(remain)?;
167 let (remain, qclass) = be_u16(remain)?;
168
169 let Ok(qtype) = QueryType::try_from(qtype) else {
170 return Err(nom::Err::Error(nom::error::make_error(
171 remain,
172 nom::error::ErrorKind::Alt,
173 )));
174 };
175 let prefer_unicast = qclass & 0x8000 == 0x8000;
176 let qclass = qclass & 0x7FFF;
177
178 let Ok(qclass) = QueryClass::try_from(qclass) else {
179 return Err(nom::Err::Error(nom::error::make_error(
180 remain,
181 nom::error::ErrorKind::Alt,
182 )));
183 };
184 Ok((
185 remain,
186 Question {
187 name,
188 prefer_unicast,
189 qtype,
190 qclass,
191 },
192 ))
193}