hickory_server/authority/
auth_lookup.rs1use std::iter::Chain;
9use std::slice::Iter;
10use std::sync::Arc;
11
12use cfg_if::cfg_if;
13
14use crate::authority::{LookupObject, LookupOptions};
15use crate::proto::rr::{LowerName, Record, RecordSet, RecordType, RrsetRecords};
16
17#[derive(Debug)]
25#[allow(clippy::large_enum_variant)]
26pub enum AuthLookup {
27 Empty,
29 Records {
32 answers: LookupRecords,
34 additionals: Option<LookupRecords>,
36 },
37 SOA(LookupRecords),
39 AXFR {
41 start_soa: LookupRecords,
43 records: LookupRecords,
45 end_soa: LookupRecords,
47 },
48}
49
50impl AuthLookup {
51 pub fn answers(answers: LookupRecords, additionals: Option<LookupRecords>) -> Self {
53 Self::Records {
54 answers,
55 additionals,
56 }
57 }
58
59 pub fn is_empty(&self) -> bool {
61 self.was_empty()
63 }
64
65 pub fn was_empty(&self) -> bool {
69 self.iter().count() == 0
70 }
71
72 pub fn iter(&self) -> AuthLookupIter<'_> {
74 self.into_iter()
75 }
76
77 pub fn unwrap_records(self) -> LookupRecords {
79 match self {
80 Self::Records { answers, .. } => answers,
82 _ => LookupRecords::default(),
83 }
84 }
85
86 pub fn take_additionals(&mut self) -> Option<LookupRecords> {
88 match self {
89 Self::Records { additionals, .. } => additionals.take(),
90 _ => None,
91 }
92 }
93}
94
95impl LookupObject for AuthLookup {
96 fn is_empty(&self) -> bool {
97 Self::is_empty(self)
98 }
99
100 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a> {
101 let boxed_iter = Self::iter(self);
102 Box::new(boxed_iter)
103 }
104
105 fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>> {
106 let additionals = Self::take_additionals(self);
107 additionals.map(|a| Box::new(a) as Box<dyn LookupObject>)
108 }
109}
110
111impl Default for AuthLookup {
112 fn default() -> Self {
113 Self::Empty
114 }
115}
116
117impl<'a> IntoIterator for &'a AuthLookup {
118 type Item = &'a Record;
119 type IntoIter = AuthLookupIter<'a>;
120
121 fn into_iter(self) -> Self::IntoIter {
122 match self {
123 AuthLookup::Empty => AuthLookupIter::Empty,
124 AuthLookup::Records { answers: r, .. } | AuthLookup::SOA(r) => {
126 AuthLookupIter::Records(r.into_iter())
127 }
128 AuthLookup::AXFR {
129 start_soa,
130 records,
131 end_soa,
132 } => AuthLookupIter::AXFR(start_soa.into_iter().chain(records).chain(end_soa)),
133 }
134 }
135}
136
137#[allow(clippy::large_enum_variant)]
139#[derive(Default)]
140pub enum AuthLookupIter<'r> {
141 #[default]
143 Empty,
144 Records(LookupRecordsIter<'r>),
146 AXFR(Chain<Chain<LookupRecordsIter<'r>, LookupRecordsIter<'r>>, LookupRecordsIter<'r>>),
148}
149
150impl<'r> Iterator for AuthLookupIter<'r> {
151 type Item = &'r Record;
152
153 fn next(&mut self) -> Option<Self::Item> {
154 match self {
155 AuthLookupIter::Empty => None,
156 AuthLookupIter::Records(i) => i.next(),
157 AuthLookupIter::AXFR(i) => i.next(),
158 }
159 }
160}
161
162impl From<LookupRecords> for AuthLookup {
163 fn from(lookup: LookupRecords) -> Self {
164 Self::Records {
165 answers: lookup,
166 additionals: None,
167 }
168 }
169}
170
171#[derive(Debug)]
180pub struct AnyRecords {
181 lookup_options: LookupOptions,
182 rrsets: Vec<Arc<RecordSet>>,
183 query_type: RecordType,
184 query_name: LowerName,
185}
186
187impl AnyRecords {
188 pub fn new(
190 lookup_options: LookupOptions,
191 rrsets: Vec<Arc<RecordSet>>,
193 query_type: RecordType,
194 query_name: LowerName,
195 ) -> Self {
196 Self {
197 lookup_options,
198 rrsets,
199 query_type,
200 query_name,
201 }
202 }
203
204 fn iter(&self) -> AnyRecordsIter<'_> {
205 self.into_iter()
206 }
207}
208
209impl<'r> IntoIterator for &'r AnyRecords {
210 type Item = &'r Record;
211 type IntoIter = AnyRecordsIter<'r>;
212
213 fn into_iter(self) -> Self::IntoIter {
214 AnyRecordsIter {
215 lookup_options: self.lookup_options,
216 rrsets: self.rrsets.iter(),
218 rrset: None,
219 records: None,
220 query_type: self.query_type,
221 query_name: &self.query_name,
222 }
223 }
224}
225
226#[allow(unused)]
228pub struct AnyRecordsIter<'r> {
229 lookup_options: LookupOptions,
230 rrsets: Iter<'r, Arc<RecordSet>>,
231 rrset: Option<&'r RecordSet>,
232 records: Option<RrsetRecords<'r>>,
233 query_type: RecordType,
234 query_name: &'r LowerName,
235}
236
237impl<'r> Iterator for AnyRecordsIter<'r> {
238 type Item = &'r Record;
239
240 fn next(&mut self) -> Option<Self::Item> {
241 use std::borrow::Borrow;
242
243 let query_type = self.query_type;
244 let query_name = self.query_name;
245
246 loop {
247 if let Some(records) = &mut self.records {
248 let record = records
249 .by_ref()
250 .filter(|rr_set| {
251 query_type == RecordType::ANY || rr_set.record_type() != RecordType::SOA
252 })
253 .find(|rr_set| {
254 query_type == RecordType::AXFR
255 || &LowerName::from(rr_set.name()) == query_name
256 });
257
258 if record.is_some() {
259 return record;
260 }
261 }
262
263 self.rrset = self.rrsets.next().map(Borrow::borrow);
264
265 self.rrset?;
267
268 cfg_if! {
270 if #[cfg(feature = "__dnssec")] {
271 self.records = Some(
272 self.rrset
273 .expect("rrset should not be None at this point")
274 .records(self.lookup_options.dnssec_ok()),
275 );
276 } else {
277 self.records = Some(self.rrset.expect("rrset should not be None at this point").records_without_rrsigs());
278 }
279 }
280 }
281 }
282}
283
284#[derive(Debug)]
286pub enum LookupRecords {
287 Empty,
289 Records {
291 lookup_options: LookupOptions,
293 records: Arc<RecordSet>,
295 },
296 ManyRecords(LookupOptions, Vec<Arc<RecordSet>>),
298 AnyRecords(AnyRecords),
301}
302
303impl LookupRecords {
304 pub fn new(lookup_options: LookupOptions, records: Arc<RecordSet>) -> Self {
306 Self::Records {
307 lookup_options,
308 records,
309 }
310 }
311
312 pub fn many(lookup_options: LookupOptions, mut records: Vec<Arc<RecordSet>>) -> Self {
314 records.reverse();
316 Self::ManyRecords(lookup_options, records)
317 }
318
319 pub fn was_empty(&self) -> bool {
323 self.iter().count() == 0
324 }
325
326 pub fn iter(&self) -> LookupRecordsIter<'_> {
328 self.into_iter()
329 }
330}
331
332impl Default for LookupRecords {
333 fn default() -> Self {
334 Self::Empty
335 }
336}
337
338impl<'a> IntoIterator for &'a LookupRecords {
339 type Item = &'a Record;
340 type IntoIter = LookupRecordsIter<'a>;
341
342 #[allow(unused_variables)]
343 fn into_iter(self) -> Self::IntoIter {
344 match self {
345 LookupRecords::Empty => LookupRecordsIter::Empty,
346 LookupRecords::Records {
347 lookup_options,
348 records,
349 } => LookupRecordsIter::RecordsIter(lookup_options.rrset_with_rrigs(records)),
350 LookupRecords::ManyRecords(lookup_options, r) => LookupRecordsIter::ManyRecordsIter(
351 r.iter()
352 .map(|r| lookup_options.rrset_with_rrigs(r))
353 .collect(),
354 None,
355 ),
356 LookupRecords::AnyRecords(r) => LookupRecordsIter::AnyRecordsIter(r.iter()),
357 }
358 }
359}
360
361#[derive(Default)]
363pub enum LookupRecordsIter<'r> {
364 AnyRecordsIter(AnyRecordsIter<'r>),
366 RecordsIter(RrsetRecords<'r>),
368 ManyRecordsIter(Vec<RrsetRecords<'r>>, Option<RrsetRecords<'r>>),
370 #[default]
372 Empty,
373}
374
375impl<'r> Iterator for LookupRecordsIter<'r> {
376 type Item = &'r Record;
377
378 fn next(&mut self) -> Option<Self::Item> {
379 match self {
380 LookupRecordsIter::Empty => None,
381 LookupRecordsIter::AnyRecordsIter(current) => current.next(),
382 LookupRecordsIter::RecordsIter(current) => current.next(),
383 LookupRecordsIter::ManyRecordsIter(set, current) => loop {
384 if let Some(o) = current.as_mut().and_then(Iterator::next) {
385 return Some(o);
386 }
387
388 *current = set.pop();
389 if current.is_none() {
390 return None;
391 }
392 },
393 }
394 }
395}
396
397impl From<AnyRecords> for LookupRecords {
398 fn from(rrset_records: AnyRecords) -> Self {
399 Self::AnyRecords(rrset_records)
400 }
401}
402
403impl LookupObject for LookupRecords {
404 fn is_empty(&self) -> bool {
405 Self::was_empty(self)
406 }
407
408 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a> {
409 Box::new(self.iter())
410 }
411
412 fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>> {
413 None
414 }
415}