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