1use std::{borrow::Borrow, collections::HashMap, future::Future, io};
12
13use cfg_if::cfg_if;
14use tracing::{debug, error, info, trace, warn};
15
16#[cfg(feature = "dnssec")]
17use crate::proto::rr::{
18 dnssec::{Algorithm, SupportedAlgorithms},
19 rdata::opt::{EdnsCode, EdnsOption},
20};
21use crate::{
22 authority::{
23 AuthLookup, AuthorityObject, EmptyLookup, LookupError, LookupObject, LookupOptions,
24 MessageResponse, MessageResponseBuilder, ZoneType,
25 },
26 proto::op::{Edns, Header, LowerQuery, MessageType, OpCode, ResponseCode},
27 proto::rr::{LowerName, Record, RecordType},
28 server::{Request, RequestHandler, RequestInfo, ResponseHandler, ResponseInfo},
29};
30
31#[derive(Default)]
33pub struct Catalog {
34 authorities: HashMap<LowerName, Box<dyn AuthorityObject>>,
35}
36
37#[allow(unused_mut, unused_variables)]
38async fn send_response<'a, R: ResponseHandler>(
39 response_edns: Option<Edns>,
40 mut response: MessageResponse<
41 '_,
42 'a,
43 impl Iterator<Item = &'a Record> + Send + 'a,
44 impl Iterator<Item = &'a Record> + Send + 'a,
45 impl Iterator<Item = &'a Record> + Send + 'a,
46 impl Iterator<Item = &'a Record> + Send + 'a,
47 >,
48 mut response_handle: R,
49) -> io::Result<ResponseInfo> {
50 if let Some(mut resp_edns) = response_edns {
51 #[cfg(feature = "dnssec")]
52 {
53 let mut algorithms = SupportedAlgorithms::default();
56 algorithms.set(Algorithm::RSASHA256);
57 algorithms.set(Algorithm::ECDSAP256SHA256);
58 algorithms.set(Algorithm::ECDSAP384SHA384);
59 algorithms.set(Algorithm::ED25519);
60
61 let dau = EdnsOption::DAU(algorithms);
62 let dhu = EdnsOption::DHU(algorithms);
63
64 resp_edns.options_mut().insert(dau);
65 resp_edns.options_mut().insert(dhu);
66 }
67 response.set_edns(resp_edns);
68 }
69
70 response_handle.send_response(response).await
71}
72
73#[async_trait::async_trait]
74impl RequestHandler for Catalog {
75 async fn handle_request<R: ResponseHandler>(
82 &self,
83 request: &Request,
84 mut response_handle: R,
85 ) -> ResponseInfo {
86 trace!("request: {:?}", request);
87
88 let response_edns: Option<Edns>;
89
90 if let Some(req_edns) = request.edns() {
92 let mut response = MessageResponseBuilder::new(Some(request.raw_query()));
93 let mut response_header = Header::response_from_request(request.header());
94
95 let mut resp_edns: Edns = Edns::new();
96
97 let our_version = 0;
100 resp_edns.set_dnssec_ok(true);
101 resp_edns.set_max_payload(req_edns.max_payload().max(512));
102 resp_edns.set_version(our_version);
103
104 if req_edns.version() > our_version {
105 warn!(
106 "request edns version greater than {}: {}",
107 our_version,
108 req_edns.version()
109 );
110 response_header.set_response_code(ResponseCode::BADVERS);
111 resp_edns.set_rcode_high(ResponseCode::BADVERS.high());
112 response.edns(resp_edns);
113
114 let result = response_handle
116 .send_response(response.build_no_records(response_header))
117 .await;
118
119 return match result {
121 Err(e) => {
122 error!("request error: {}", e);
123 ResponseInfo::serve_failed()
124 }
125 Ok(info) => info,
126 };
127 }
128
129 response_edns = Some(resp_edns);
130 } else {
131 response_edns = None;
132 }
133
134 let result = match request.message_type() {
135 MessageType::Query => match request.op_code() {
138 OpCode::Query => {
139 debug!("query received: {}", request.id());
140 let info = self.lookup(request, response_edns, response_handle).await;
141
142 Ok(info)
143 }
144 OpCode::Update => {
145 debug!("update received: {}", request.id());
146 self.update(request, response_edns, response_handle).await
147 }
148 c => {
149 warn!("unimplemented op_code: {:?}", c);
150 let response = MessageResponseBuilder::new(Some(request.raw_query()));
151
152 response_handle
153 .send_response(response.error_msg(request.header(), ResponseCode::NotImp))
154 .await
155 }
156 },
157 MessageType::Response => {
158 warn!("got a response as a request from id: {}", request.id());
159 let response = MessageResponseBuilder::new(Some(request.raw_query()));
160
161 response_handle
162 .send_response(response.error_msg(request.header(), ResponseCode::FormErr))
163 .await
164 }
165 };
166
167 match result {
168 Err(e) => {
169 error!("request failed: {}", e);
170 ResponseInfo::serve_failed()
171 }
172 Ok(info) => info,
173 }
174 }
175}
176
177impl Catalog {
178 pub fn new() -> Self {
180 Self {
181 authorities: HashMap::new(),
182 }
183 }
184
185 pub fn upsert(&mut self, name: LowerName, authority: Box<dyn AuthorityObject>) {
192 self.authorities.insert(name, authority);
193 }
194
195 pub fn remove(&mut self, name: &LowerName) -> Option<Box<dyn AuthorityObject>> {
197 self.authorities.remove(name)
198 }
199
200 pub async fn update<R: ResponseHandler>(
250 &self,
251 update: &Request,
252 response_edns: Option<Edns>,
253 response_handle: R,
254 ) -> io::Result<ResponseInfo> {
255 let request_info = update.request_info();
256
257 let verify_request = move || -> Result<RequestInfo<'_>, ResponseCode> {
258 let ztype = request_info.query.query_type();
266
267 if ztype != RecordType::SOA {
268 warn!(
269 "invalid update request zone type must be SOA, ztype: {}",
270 ztype
271 );
272 return Err(ResponseCode::FormErr);
273 }
274
275 Ok(request_info)
276 };
277
278 let request_info = verify_request();
280 let authority = request_info.as_ref().map_err(|e| *e).and_then(|info| {
281 self.find(info.query.name())
282 .map(|a| a.box_clone())
283 .ok_or(ResponseCode::Refused)
284 });
285
286 let response_code = match authority {
287 Ok(authority) => {
288 #[allow(deprecated)]
289 match authority.zone_type() {
290 ZoneType::Secondary | ZoneType::Slave => {
291 error!("secondary forwarding for update not yet implemented");
292 ResponseCode::NotImp
293 }
294 ZoneType::Primary | ZoneType::Master => {
295 let update_result = authority.update(update).await;
296 match update_result {
297 Ok(..) => ResponseCode::NoError,
299 Err(response_code) => response_code,
300 }
301 }
302 _ => ResponseCode::NotAuth,
303 }
304 }
305 Err(response_code) => response_code,
306 };
307
308 let response = MessageResponseBuilder::new(Some(update.raw_query()));
309 let mut response_header = Header::default();
310 response_header.set_id(update.id());
311 response_header.set_op_code(OpCode::Update);
312 response_header.set_message_type(MessageType::Response);
313 response_header.set_response_code(response_code);
314
315 send_response(
316 response_edns,
317 response.build_no_records(response_header),
318 response_handle,
319 )
320 .await
321 }
322
323 pub fn contains(&self, name: &LowerName) -> bool {
333 self.authorities.contains_key(name)
334 }
335
336 pub async fn lookup<R: ResponseHandler>(
343 &self,
344 request: &Request,
345 response_edns: Option<Edns>,
346 response_handle: R,
347 ) -> ResponseInfo {
348 let request_info = request.request_info();
349 let authority = self.find(request_info.query.name());
350
351 if let Some(authority) = authority {
352 lookup(
353 request_info,
354 authority,
355 request,
356 response_edns
357 .as_ref()
358 .map(|arc| Borrow::<Edns>::borrow(arc).clone()),
359 response_handle.clone(),
360 )
361 .await
362 } else {
363 let response = MessageResponseBuilder::new(Some(request.raw_query()));
365
366 let result = send_response(
367 response_edns,
368 response.error_msg(request.header(), ResponseCode::Refused),
369 response_handle,
370 )
371 .await;
372
373 match result {
374 Err(e) => {
375 error!("failed to send response: {}", e);
376 ResponseInfo::serve_failed()
377 }
378 Ok(r) => r,
379 }
380 }
381 }
382
383 pub fn find(&self, name: &LowerName) -> Option<&(dyn AuthorityObject + 'static)> {
385 debug!("searching authorities for: {}", name);
386 self.authorities
387 .get(name)
388 .map(|authority| &**authority)
389 .or_else(|| {
390 if !name.is_root() {
391 let name = name.base_name();
392 self.find(&name)
393 } else {
394 None
395 }
396 })
397 }
398}
399
400async fn lookup<R: ResponseHandler + Unpin>(
401 request_info: RequestInfo<'_>,
402 authority: &dyn AuthorityObject,
403 request: &Request,
404 response_edns: Option<Edns>,
405 response_handle: R,
406) -> ResponseInfo {
407 let query = request_info.query;
408 debug!(
409 "request: {} found authority: {}",
410 request.id(),
411 authority.origin()
412 );
413
414 let (response_header, sections) = build_response(
415 authority,
416 request_info,
417 request.id(),
418 request.header(),
419 query,
420 request.edns(),
421 )
422 .await;
423
424 let response = MessageResponseBuilder::new(Some(request.raw_query())).build(
425 response_header,
426 sections.answers.iter(),
427 sections.ns.iter(),
428 sections.soa.iter(),
429 sections.additionals.iter(),
430 );
431
432 let result = send_response(response_edns.clone(), response, response_handle.clone()).await;
433
434 match result {
435 Err(e) => {
436 error!("error sending response: {}", e);
437 ResponseInfo::serve_failed()
438 }
439 Ok(i) => i,
440 }
441}
442
443#[allow(unused_variables)]
444fn lookup_options_for_edns(edns: Option<&Edns>) -> LookupOptions {
445 let edns = match edns {
446 Some(edns) => edns,
447 None => return LookupOptions::default(),
448 };
449
450 cfg_if! {
451 if #[cfg(feature = "dnssec")] {
452 let supported_algorithms = if let Some(&EdnsOption::DAU(algs)) = edns.option(EdnsCode::DAU)
453 {
454 algs
455 } else {
456 debug!("no DAU in request, used default SupportAlgorithms");
457 SupportedAlgorithms::default()
458 };
459
460 LookupOptions::for_dnssec(edns.dnssec_ok(), supported_algorithms)
461 } else {
462 LookupOptions::default()
463 }
464 }
465}
466
467async fn build_response(
468 authority: &dyn AuthorityObject,
469 request_info: RequestInfo<'_>,
470 request_id: u16,
471 request_header: &Header,
472 query: &LowerQuery,
473 edns: Option<&Edns>,
474) -> (Header, LookupSections) {
475 let lookup_options = lookup_options_for_edns(edns);
476
477 if lookup_options.is_dnssec() {
479 info!(
480 "request: {} lookup_options: {:?}",
481 request_id, lookup_options
482 );
483 }
484
485 let mut response_header = Header::response_from_request(request_header);
486 response_header.set_authoritative(authority.zone_type().is_authoritative());
487
488 debug!("performing {} on {}", query, authority.origin());
489 let future = authority.search(request_info, lookup_options);
490
491 #[allow(deprecated)]
492 let sections = match authority.zone_type() {
493 ZoneType::Primary | ZoneType::Secondary | ZoneType::Master | ZoneType::Slave => {
494 send_authoritative_response(
495 future,
496 authority,
497 &mut response_header,
498 lookup_options,
499 request_id,
500 query,
501 )
502 .await
503 }
504 ZoneType::Forward | ZoneType::Hint => {
505 send_forwarded_response(future, request_header, &mut response_header).await
506 }
507 };
508
509 (response_header, sections)
510}
511
512async fn send_authoritative_response(
513 future: impl Future<Output = Result<Box<dyn LookupObject>, LookupError>>,
514 authority: &dyn AuthorityObject,
515 response_header: &mut Header,
516 lookup_options: LookupOptions,
517 request_id: u16,
518 query: &LowerQuery,
519) -> LookupSections {
520 let answers = match future.await {
525 Ok(records) => {
526 response_header.set_response_code(ResponseCode::NoError);
527 response_header.set_authoritative(true);
528 Some(records)
529 }
530 Err(LookupError::ResponseCode(ResponseCode::Refused)) => {
533 response_header.set_response_code(ResponseCode::Refused);
534 return LookupSections {
535 answers: Box::<AuthLookup>::default(),
536 ns: Box::<AuthLookup>::default(),
537 soa: Box::<AuthLookup>::default(),
538 additionals: Box::<AuthLookup>::default(),
539 };
540 }
541 Err(e) => {
542 if e.is_nx_domain() {
543 response_header.set_response_code(ResponseCode::NXDomain);
544 } else if e.is_name_exists() {
545 response_header.set_response_code(ResponseCode::NoError);
546 };
547 None
548 }
549 };
550
551 let (ns, soa) = if answers.is_some() {
552 if query.query_type().is_soa() {
554 match authority.ns(lookup_options).await {
557 Ok(ns) => (Some(ns), None),
558 Err(e) => {
559 warn!("ns_lookup errored: {}", e);
560 (None, None)
561 }
562 }
563 } else {
564 (None, None)
565 }
566 } else {
567 let nsecs = if lookup_options.is_dnssec() {
568 debug!("request: {} non-existent adding nsecs", request_id);
570 let future = authority.get_nsec_records(query.name(), lookup_options);
572 match future.await {
573 Ok(nsecs) => Some(nsecs),
575 Err(e) => {
576 warn!("failed to lookup nsecs: {}", e);
577 None
578 }
579 }
580 } else {
581 None
582 };
583
584 match authority.soa_secure(lookup_options).await {
585 Ok(soa) => (nsecs, Some(soa)),
586 Err(e) => {
587 warn!("failed to lookup soa: {}", e);
588 (nsecs, None)
589 }
590 }
591 };
592
593 let (answers, additionals) = match answers {
595 Some(mut answers) => match answers.take_additionals() {
596 Some(additionals) => (answers, additionals),
597 None => (
598 answers,
599 Box::<AuthLookup>::default() as Box<dyn LookupObject>,
600 ),
601 },
602 None => (
603 Box::<AuthLookup>::default() as Box<dyn LookupObject>,
604 Box::<AuthLookup>::default() as Box<dyn LookupObject>,
605 ),
606 };
607
608 LookupSections {
609 answers,
610 ns: ns.unwrap_or_else(|| Box::<AuthLookup>::default()),
611 soa: soa.unwrap_or_else(|| Box::<AuthLookup>::default()),
612 additionals,
613 }
614}
615
616async fn send_forwarded_response(
617 future: impl Future<Output = Result<Box<dyn LookupObject>, LookupError>>,
618 request_header: &Header,
619 response_header: &mut Header,
620) -> LookupSections {
621 response_header.set_recursion_available(true);
622 response_header.set_authoritative(false);
623
624 let answers = if !request_header.recursion_desired() {
626 drop(future);
629
630 info!(
631 "request disabled recursion, returning no records: {}",
632 request_header.id()
633 );
634
635 Box::new(EmptyLookup)
636 } else {
637 match future.await {
638 Err(e) => {
639 if e.is_nx_domain() {
640 response_header.set_response_code(ResponseCode::NXDomain);
641 }
642 debug!("error resolving: {}", e);
643 Box::new(EmptyLookup)
644 }
645 Ok(rsp) => rsp,
646 }
647 };
648
649 LookupSections {
650 answers,
651 ns: Box::<AuthLookup>::default(),
652 soa: Box::<AuthLookup>::default(),
653 additionals: Box::<AuthLookup>::default(),
654 }
655}
656
657struct LookupSections {
658 answers: Box<dyn LookupObject>,
659 ns: Box<dyn LookupObject>,
660 soa: Box<dyn LookupObject>,
661 additionals: Box<dyn LookupObject>,
662}