hickory_server/zone_handler/
auth_lookup.rs1use std::mem;
9use std::slice::Iter;
10use std::sync::Arc;
11
12use crate::proto::{
13 op::Message,
14 rr::{Record, RecordSet, RecordType, RrsetRecords},
15};
16#[cfg(feature = "resolver")]
17use crate::resolver::lookup::Lookup;
18use crate::zone_handler::LookupOptions;
19
20#[allow(clippy::large_enum_variant)]
22#[derive(Debug, Default)]
23#[non_exhaustive]
24pub enum AuthLookup {
25 #[default]
27 Empty,
28 Records {
31 answers: LookupRecords,
33 additionals: Option<LookupRecords>,
35 },
36 #[cfg(feature = "resolver")]
38 Resolved(Lookup),
39 Response(Message),
41}
42
43impl AuthLookup {
44 pub fn answers(answers: LookupRecords, additionals: Option<LookupRecords>) -> Self {
46 Self::Records {
47 answers,
48 additionals,
49 }
50 }
51
52 pub fn is_empty(&self) -> bool {
54 self.was_empty()
56 }
57
58 pub fn was_empty(&self) -> bool {
62 self.iter().count() == 0
63 }
64
65 pub fn iter(&self) -> AuthLookupIter<'_> {
67 self.into_iter()
68 }
69
70 pub fn unwrap_records(self) -> LookupRecords {
72 match self {
73 Self::Records { answers, .. } => answers,
75 _ => LookupRecords::default(),
76 }
77 }
78
79 pub fn authorities(&self) -> Option<LookupRecordsIter<'_>> {
81 match self {
82 Self::Response(message) => {
83 Some(LookupRecordsIter::SliceIter(message.authorities.iter()))
84 }
85 _ => None,
86 }
87 }
88
89 pub fn additionals(&self) -> Option<LookupRecordsIter<'_>> {
91 match self {
92 Self::Records { additionals, .. } => additionals.as_ref().map(|l| l.iter()),
93 Self::Response(message) => {
94 Some(LookupRecordsIter::SliceIter(message.additionals.iter()))
95 }
96 _ => None,
97 }
98 }
99
100 pub fn take_additionals(&mut self) -> Option<LookupRecords> {
102 match self {
103 Self::Records { additionals, .. } => additionals.take(),
104 Self::Response(message) => {
105 Some(LookupRecords::Section(mem::take(&mut message.additionals)))
106 }
107 _ => None,
108 }
109 }
110}
111
112#[cfg(feature = "resolver")]
113impl From<Lookup> for AuthLookup {
114 fn from(lookup: Lookup) -> Self {
115 Self::Resolved(lookup)
116 }
117}
118
119impl<'a> IntoIterator for &'a AuthLookup {
120 type Item = &'a Record;
121 type IntoIter = AuthLookupIter<'a>;
122
123 fn into_iter(self) -> Self::IntoIter {
124 match self {
125 AuthLookup::Empty => AuthLookupIter::Empty,
126 AuthLookup::Records { answers: r, .. } => AuthLookupIter::Records(r.into_iter()),
128 #[cfg(feature = "resolver")]
129 AuthLookup::Resolved(lookup) => AuthLookupIter::Response(lookup.answers().iter()),
130 AuthLookup::Response(message) => AuthLookupIter::Response(message.answers.iter()),
131 }
132 }
133}
134
135#[derive(Default)]
137pub enum AuthLookupIter<'r> {
138 #[default]
140 Empty,
141 Records(LookupRecordsIter<'r>),
143 Response(Iter<'r, Record>),
145}
146
147impl<'r> Iterator for AuthLookupIter<'r> {
148 type Item = &'r Record;
149
150 fn next(&mut self) -> Option<Self::Item> {
151 match self {
152 AuthLookupIter::Empty => None,
153 AuthLookupIter::Records(i) => i.next(),
154 AuthLookupIter::Response(i) => i.next(),
155 }
156 }
157}
158
159impl From<LookupRecords> for AuthLookup {
160 fn from(lookup: LookupRecords) -> Self {
161 Self::Records {
162 answers: lookup,
163 additionals: None,
164 }
165 }
166}
167
168#[derive(Debug)]
172pub struct AxfrRecords {
173 dnssec_ok: bool,
174 rrsets: Vec<Arc<RecordSet>>,
175}
176
177impl AxfrRecords {
178 pub fn new(dnssec_ok: bool, rrsets: Vec<Arc<RecordSet>>) -> Self {
180 Self { dnssec_ok, rrsets }
181 }
182
183 fn iter(&self) -> AxfrRecordsIter<'_> {
184 self.into_iter()
185 }
186}
187
188impl<'r> IntoIterator for &'r AxfrRecords {
189 type Item = &'r Record;
190 type IntoIter = AxfrRecordsIter<'r>;
191
192 fn into_iter(self) -> Self::IntoIter {
193 AxfrRecordsIter {
194 dnssec_ok: self.dnssec_ok,
195 rrsets: self.rrsets.iter(),
196 records: None,
197 }
198 }
199}
200
201pub struct AxfrRecordsIter<'r> {
203 #[cfg_attr(not(feature = "__dnssec"), allow(dead_code))]
204 dnssec_ok: bool,
205 rrsets: Iter<'r, Arc<RecordSet>>,
206 records: Option<RrsetRecords<'r>>,
207}
208
209impl<'r> Iterator for AxfrRecordsIter<'r> {
210 type Item = &'r Record;
211
212 fn next(&mut self) -> Option<Self::Item> {
213 loop {
214 if let Some(records) = &mut self.records {
215 if let Some(record) = records
216 .by_ref()
217 .find(|record| record.record_type() != RecordType::SOA)
218 {
219 return Some(record);
220 }
221 }
222
223 let rrset = self.rrsets.next()?;
225
226 #[cfg(feature = "__dnssec")]
227 let records = rrset.records(self.dnssec_ok);
228
229 #[cfg(not(feature = "__dnssec"))]
230 let records = rrset.records_without_rrsigs();
231
232 self.records = Some(records);
233 }
234 }
235}
236
237#[derive(Debug, Default)]
239pub enum LookupRecords {
240 #[default]
242 Empty,
243 Records {
245 lookup_options: LookupOptions,
247 records: Arc<RecordSet>,
249 },
250 ManyRecords(LookupOptions, Vec<Arc<RecordSet>>),
252 Section(Vec<Record>),
254}
255
256impl LookupRecords {
257 pub fn new(lookup_options: LookupOptions, records: Arc<RecordSet>) -> Self {
259 Self::Records {
260 lookup_options,
261 records,
262 }
263 }
264
265 pub fn many(lookup_options: LookupOptions, mut records: Vec<Arc<RecordSet>>) -> Self {
267 records.reverse();
269 Self::ManyRecords(lookup_options, records)
270 }
271
272 pub fn was_empty(&self) -> bool {
276 self.iter().count() == 0
277 }
278
279 pub fn iter(&self) -> LookupRecordsIter<'_> {
281 self.into_iter()
282 }
283}
284
285impl<'a> IntoIterator for &'a LookupRecords {
286 type Item = &'a Record;
287 type IntoIter = LookupRecordsIter<'a>;
288
289 fn into_iter(self) -> Self::IntoIter {
290 match self {
291 LookupRecords::Empty => LookupRecordsIter::Empty,
292 LookupRecords::Records {
293 lookup_options,
294 records,
295 } => LookupRecordsIter::RecordsIter(lookup_options.rrset_with_rrigs(records)),
296 LookupRecords::ManyRecords(lookup_options, r) => LookupRecordsIter::ManyRecordsIter(
297 r.iter()
298 .map(|r| lookup_options.rrset_with_rrigs(r))
299 .collect(),
300 None,
301 ),
302 LookupRecords::Section(vec) => LookupRecordsIter::SliceIter(vec.iter()),
303 }
304 }
305}
306
307#[derive(Default)]
309pub enum LookupRecordsIter<'r> {
310 RecordsIter(RrsetRecords<'r>),
312 ManyRecordsIter(Vec<RrsetRecords<'r>>, Option<RrsetRecords<'r>>),
314 SliceIter(Iter<'r, Record>),
316 #[default]
318 Empty,
319}
320
321impl<'r> Iterator for LookupRecordsIter<'r> {
322 type Item = &'r Record;
323
324 fn next(&mut self) -> Option<Self::Item> {
325 match self {
326 LookupRecordsIter::Empty => None,
327 LookupRecordsIter::RecordsIter(current) => current.next(),
328 LookupRecordsIter::SliceIter(current) => current.next(),
329 LookupRecordsIter::ManyRecordsIter(set, current) => loop {
330 if let Some(o) = current.as_mut().and_then(Iterator::next) {
331 return Some(o);
332 }
333
334 *current = set.pop();
335 if current.is_none() {
336 return None;
337 }
338 },
339 }
340 }
341}
342
343#[derive(Debug)]
347pub struct ZoneTransfer {
348 pub start_soa: LookupRecords,
352 pub records: AxfrRecords,
354 pub end_soa: LookupRecords,
358}
359
360impl ZoneTransfer {
361 pub fn iter(&self) -> impl Iterator<Item = &Record> {
363 self.start_soa
364 .iter()
365 .chain(self.records.iter())
366 .chain(self.end_soa.iter())
367 }
368}