trust_dns_server/store/recursor/
authority.rs

1// Copyright 2015-2022 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use std::{io, path::Path, time::Instant};
9
10use tracing::{debug, info};
11
12use crate::{
13    authority::{
14        Authority, LookupError, LookupObject, LookupOptions, MessageRequest, UpdateResult, ZoneType,
15    },
16    proto::{
17        op::{Query, ResponseCode},
18        rr::{LowerName, Name, Record, RecordType},
19    },
20    recursor::Recursor,
21    resolver::{
22        config::{NameServerConfig, NameServerConfigGroup, Protocol},
23        lookup::Lookup,
24    },
25    server::RequestInfo,
26    store::recursor::RecursiveConfig,
27};
28
29/// An authority that will forward resolutions to upstream resolvers.
30///
31/// This uses the trust-dns-resolver for resolving requests.
32pub struct RecursiveAuthority {
33    origin: LowerName,
34    recursor: Recursor,
35}
36
37impl RecursiveAuthority {
38    /// Read the Authority for the origin from the specified configuration
39    pub async fn try_from_config(
40        origin: Name,
41        _zone_type: ZoneType,
42        config: &RecursiveConfig,
43        root_dir: Option<&Path>,
44    ) -> Result<Self, String> {
45        info!("loading recursor config: {}", origin);
46
47        // read the roots
48        let root_addrs = config
49            .read_roots(root_dir)
50            .map_err(|e| format!("failed to read roots {}: {}", config.roots.display(), e))?;
51
52        // Configure all the name servers
53        let mut roots = NameServerConfigGroup::new();
54        for socket_addr in root_addrs {
55            roots.push(NameServerConfig {
56                socket_addr,
57                protocol: Protocol::Tcp,
58                tls_dns_name: None,
59                trust_negative_responses: false,
60                #[cfg(feature = "dns-over-rustls")]
61                tls_config: None,
62                bind_addr: None, // TODO: need to support bind addresses
63            });
64
65            roots.push(NameServerConfig {
66                socket_addr,
67                protocol: Protocol::Udp,
68                tls_dns_name: None,
69                trust_negative_responses: false,
70                #[cfg(feature = "dns-over-rustls")]
71                tls_config: None,
72                bind_addr: None,
73            });
74        }
75
76        let recursor =
77            Recursor::new(roots).map_err(|e| format!("failed to initialize recursor: {e}"))?;
78
79        Ok(Self {
80            origin: origin.into(),
81            recursor,
82        })
83    }
84}
85
86#[async_trait::async_trait]
87impl Authority for RecursiveAuthority {
88    type Lookup = RecursiveLookup;
89
90    /// Always Recursive
91    fn zone_type(&self) -> ZoneType {
92        ZoneType::Hint
93    }
94
95    /// Always false for Forward zones
96    fn is_axfr_allowed(&self) -> bool {
97        false
98    }
99
100    async fn update(&self, _update: &MessageRequest) -> UpdateResult<bool> {
101        Err(ResponseCode::NotImp)
102    }
103
104    /// Get the origin of this zone, i.e. example.com is the origin for www.example.com
105    ///
106    /// In the context of a forwarder, this is either a zone which this forwarder is associated,
107    ///   or `.`, the root zone for all zones. If this is not the root zone, then it will only forward
108    ///   for lookups which match the given zone name.
109    fn origin(&self) -> &LowerName {
110        &self.origin
111    }
112
113    /// Forwards a lookup given the resolver configuration for this Forwarded zone
114    async fn lookup(
115        &self,
116        name: &LowerName,
117        rtype: RecordType,
118        _lookup_options: LookupOptions,
119    ) -> Result<Self::Lookup, LookupError> {
120        debug!("recursive lookup: {} {}", name, rtype);
121
122        let query = Query::query(name.into(), rtype);
123        let now = Instant::now();
124
125        self.recursor
126            .resolve(query, now)
127            .await
128            .map(RecursiveLookup)
129            .map_err(Into::into)
130    }
131
132    async fn search(
133        &self,
134        request_info: RequestInfo<'_>,
135        lookup_options: LookupOptions,
136    ) -> Result<Self::Lookup, LookupError> {
137        self.lookup(
138            request_info.query.name(),
139            request_info.query.query_type(),
140            lookup_options,
141        )
142        .await
143    }
144
145    async fn get_nsec_records(
146        &self,
147        _name: &LowerName,
148        _lookup_options: LookupOptions,
149    ) -> Result<Self::Lookup, LookupError> {
150        Err(LookupError::from(io::Error::new(
151            io::ErrorKind::Other,
152            "Getting NSEC records is unimplemented for the recursor",
153        )))
154    }
155}
156
157pub struct RecursiveLookup(Lookup);
158
159impl LookupObject for RecursiveLookup {
160    fn is_empty(&self) -> bool {
161        self.0.is_empty()
162    }
163
164    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a> {
165        Box::new(self.0.record_iter())
166    }
167
168    fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>> {
169        None
170    }
171}