hickory_proto/serialize/txt/
parse_rdata.rs1use alloc::vec::Vec;
10
11#[cfg(feature = "__dnssec")]
12use crate::dnssec::rdata::DNSSECRData;
13use crate::{
14 rr::{
15 Name, RData, RecordType,
16 rdata::{ANAME, CNAME, HTTPS, NS, PTR},
17 },
18 serialize::txt::{
19 errors::{ParseError, ParseErrorKind, ParseResult},
20 rdata_parsers::*,
21 zone_lex::Lexer,
22 },
23};
24
25use super::Token;
26
27pub trait RDataParser: Sized {
29 fn parse<'i, I: Iterator<Item = &'i str>>(
31 record_type: RecordType,
32 tokens: I,
33 origin: Option<&Name>,
34 ) -> ParseResult<Self>;
35
36 fn try_from_str(record_type: RecordType, s: &str) -> ParseResult<Self> {
38 let mut lexer = Lexer::new(s);
39 let mut rdata = Vec::new();
40
41 while let Some(token) = lexer.next_token()? {
42 match token {
43 Token::List(list) => rdata.extend(list),
44 Token::CharData(s) => rdata.push(s),
45 Token::EOL | Token::Blank => (),
46 _ => {
47 return Err(ParseError::from(format!(
48 "unexpected token in record data: {token:?}"
49 )));
50 }
51 }
52 }
53
54 Self::parse(record_type, rdata.iter().map(AsRef::as_ref), None)
55 }
56}
57
58#[warn(clippy::wildcard_enum_match_arm)] impl RDataParser for RData {
60 fn parse<'i, I: Iterator<Item = &'i str>>(
62 record_type: RecordType,
63 tokens: I,
64 origin: Option<&Name>,
65 ) -> ParseResult<Self> {
66 let rdata = match record_type {
67 RecordType::A => Self::A(a::parse(tokens)?),
68 RecordType::AAAA => Self::AAAA(aaaa::parse(tokens)?),
69 RecordType::ANAME => Self::ANAME(ANAME(name::parse(tokens, origin)?)),
70 RecordType::ANY => return Err(ParseError::from("parsing ANY doesn't make sense")),
71 RecordType::AXFR => return Err(ParseError::from("parsing AXFR doesn't make sense")),
72 RecordType::CAA => caa::parse(tokens).map(Self::CAA)?,
73 RecordType::CERT => Self::CERT(cert::parse(tokens)?),
74 RecordType::CNAME => Self::CNAME(CNAME(name::parse(tokens, origin)?)),
75 RecordType::CSYNC => csync::parse(tokens).map(Self::CSYNC)?,
76 RecordType::HINFO => Self::HINFO(hinfo::parse(tokens)?),
77 RecordType::HTTPS => svcb::parse(tokens).map(HTTPS).map(Self::HTTPS)?,
78 RecordType::IXFR => return Err(ParseError::from("parsing IXFR doesn't make sense")),
79 RecordType::MX => Self::MX(mx::parse(tokens, origin)?),
80 RecordType::NAPTR => Self::NAPTR(naptr::parse(tokens, origin)?),
81 RecordType::NULL => Self::NULL(null::parse(tokens)?),
82 RecordType::NS => Self::NS(NS(name::parse(tokens, origin)?)),
83 RecordType::OPENPGPKEY => Self::OPENPGPKEY(openpgpkey::parse(tokens)?),
84 RecordType::OPT => return Err(ParseError::from("parsing OPT doesn't make sense")),
85 RecordType::PTR => Self::PTR(PTR(name::parse(tokens, origin)?)),
86 RecordType::SOA => Self::SOA(soa::parse(tokens, origin)?),
87 RecordType::SRV => Self::SRV(srv::parse(tokens, origin)?),
88 RecordType::SSHFP => Self::SSHFP(sshfp::parse(tokens)?),
89 RecordType::SVCB => svcb::parse(tokens).map(Self::SVCB)?,
90 RecordType::TLSA => Self::TLSA(tlsa::parse(tokens)?),
91 RecordType::TXT => Self::TXT(txt::parse(tokens)?),
92 RecordType::SIG => return Err(ParseError::from("parsing SIG doesn't make sense")),
93 RecordType::DNSKEY => {
94 return Err(ParseError::from("DNSKEY should be dynamically generated"));
95 }
96 RecordType::CDNSKEY => {
97 return Err(ParseError::from("CDNSKEY should be dynamically generated"));
98 }
99 RecordType::KEY => return Err(ParseError::from("KEY should be dynamically generated")),
100 #[cfg(feature = "__dnssec")]
101 RecordType::DS => Self::DNSSEC(DNSSECRData::DS(ds::parse(tokens)?)),
102 #[cfg(not(feature = "__dnssec"))]
103 RecordType::DS => return Err(ParseError::from("DS should be dynamically generated")),
104 RecordType::CDS => return Err(ParseError::from("CDS should be dynamically generated")),
105 RecordType::NSEC => {
106 return Err(ParseError::from("NSEC should be dynamically generated"));
107 }
108 RecordType::NSEC3 => {
109 return Err(ParseError::from("NSEC3 should be dynamically generated"));
110 }
111 RecordType::NSEC3PARAM => {
112 return Err(ParseError::from(
113 "NSEC3PARAM should be dynamically generated",
114 ));
115 }
116 RecordType::RRSIG => {
117 return Err(ParseError::from("RRSIG should be dynamically generated"));
118 }
119 RecordType::TSIG => return Err(ParseError::from("TSIG is only used during AXFR")),
120 #[allow(deprecated)]
121 RecordType::ZERO => Self::ZERO,
122 r @ RecordType::Unknown(..) => {
123 return Err(ParseError::from(ParseErrorKind::UnsupportedRecordType(r)));
125 }
126 };
127
128 Ok(rdata)
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 #![allow(clippy::dbg_macro, clippy::print_stdout)]
135
136 use super::*;
137 #[cfg(feature = "__dnssec")]
138 use crate::dnssec::rdata::DS;
139 use crate::rr::domain::Name;
140 use crate::rr::rdata::*;
141 use core::str::FromStr;
142
143 #[test]
144 fn test_a() {
145 let tokens = ["192.168.0.1"];
146 let name = Name::from_str("example.com.").unwrap();
147 let record =
148 RData::parse(RecordType::A, tokens.iter().map(AsRef::as_ref), Some(&name)).unwrap();
149
150 assert_eq!(record, RData::A("192.168.0.1".parse().unwrap()));
151 }
152
153 #[test]
154 fn test_a_parse() {
155 let data = "192.168.0.1";
156 let record = RData::try_from_str(RecordType::A, data).unwrap();
157
158 assert_eq!(record, RData::A("192.168.0.1".parse().unwrap()));
159 }
160
161 #[test]
162 fn test_aaaa() {
163 let tokens = ["::1"];
164 let name = Name::from_str("example.com.").unwrap();
165 let record = RData::parse(
166 RecordType::AAAA,
167 tokens.iter().map(AsRef::as_ref),
168 Some(&name),
169 )
170 .unwrap();
171
172 assert_eq!(record, RData::AAAA("::1".parse().unwrap()));
173 }
174
175 #[test]
176 fn test_aaaa_parse() {
177 let data = "::1";
178 let record = RData::try_from_str(RecordType::AAAA, data).unwrap();
179
180 assert_eq!(record, RData::AAAA("::1".parse().unwrap()));
181 }
182
183 #[test]
184 fn test_ns_parse() {
185 let data = "ns.example.com";
186 let record = RData::try_from_str(RecordType::NS, data).unwrap();
187
188 assert_eq!(
189 record,
190 RData::NS(NS(Name::from_str("ns.example.com").unwrap()))
191 );
192 }
193
194 #[test]
195 fn test_csync() {
196 let tokens = ["123", "1", "A", "NS"];
197 let name = Name::from_str("example.com.").unwrap();
198 let record = RData::parse(
199 RecordType::CSYNC,
200 tokens.iter().map(AsRef::as_ref),
201 Some(&name),
202 )
203 .unwrap();
204
205 assert_eq!(
206 record,
207 RData::CSYNC(CSYNC::new(
208 123,
209 true,
210 false,
211 [RecordType::A, RecordType::NS]
212 ))
213 );
214 }
215
216 #[test]
217 fn test_csync_parse() {
218 let data = "123 1 A NS";
219 let record = RData::try_from_str(RecordType::CSYNC, data).unwrap();
220
221 assert_eq!(
222 record,
223 RData::CSYNC(CSYNC::new(
224 123,
225 true,
226 false,
227 [RecordType::A, RecordType::NS]
228 ))
229 );
230 }
231
232 #[cfg(feature = "__dnssec")]
233 #[test]
234 #[allow(deprecated)]
235 fn test_ds() {
236 let tokens = [
237 "60485",
238 "5",
239 "1",
240 "2BB183AF5F22588179A53B0A",
241 "98631FAD1A292118",
242 ];
243 let name = Name::from_str("dskey.example.com.").unwrap();
244 let record = RData::parse(
245 RecordType::DS,
246 tokens.iter().map(AsRef::as_ref),
247 Some(&name),
248 )
249 .unwrap();
250
251 assert_eq!(
252 record,
253 RData::DNSSEC(DNSSECRData::DS(DS::new(
254 60485,
255 crate::dnssec::Algorithm::RSASHA1,
256 crate::dnssec::DigestType::SHA1,
257 vec![
258 0x2B, 0xB1, 0x83, 0xAF, 0x5F, 0x22, 0x58, 0x81, 0x79, 0xA5, 0x3B, 0x0A, 0x98,
259 0x63, 0x1F, 0xAD, 0x1A, 0x29, 0x21, 0x18
260 ]
261 )))
262 );
263 }
264
265 #[test]
266 fn test_any() {
267 let tokens = ["test"];
268 let name = Name::from_str("example.com.").unwrap();
269 let result = RData::parse(
270 RecordType::ANY,
271 tokens.iter().map(AsRef::as_ref),
272 Some(&name),
273 );
274
275 assert!(result.is_err());
276 }
277
278 #[test]
279 fn test_dynamically_generated() {
280 let dynamically_generated = vec![
281 RecordType::DS,
282 RecordType::CDS,
283 RecordType::DNSKEY,
284 RecordType::CDNSKEY,
285 RecordType::KEY,
286 RecordType::NSEC,
287 RecordType::NSEC3,
288 RecordType::NSEC3PARAM,
289 RecordType::RRSIG,
290 ];
291
292 let tokens = ["test"];
293
294 let name = Name::from_str("example.com.").unwrap();
295
296 for record_type in dynamically_generated {
297 let result = RData::parse(record_type, tokens.iter().map(AsRef::as_ref), Some(&name));
298 assert!(result.is_err());
299 }
300 }
301}