trust_dns_server/authority/authority.rs
1// Copyright 2015-2021 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
8//! All authority related types
9
10use cfg_if::cfg_if;
11
12#[cfg(feature = "dnssec")]
13use crate::proto::rr::{
14 dnssec::{rdata::key::KEY, DnsSecResult, SigSigner, SupportedAlgorithms},
15 Name,
16};
17use crate::{
18 authority::{LookupError, MessageRequest, UpdateResult, ZoneType},
19 proto::rr::{LowerName, RecordSet, RecordType, RrsetRecords},
20 server::RequestInfo,
21};
22
23/// LookupOptions that specify different options from the client to include or exclude various records in the response.
24///
25/// For example, `is_dnssec` will include `RRSIG` in the response, `supported_algorithms` will only include a subset of
26/// `RRSIG` based on the algorithms supported by the request.
27#[derive(Clone, Copy, Debug, Default)]
28pub struct LookupOptions {
29 is_dnssec: bool,
30 #[cfg(feature = "dnssec")]
31 supported_algorithms: SupportedAlgorithms,
32}
33
34/// Lookup Options for the request to the authority
35impl LookupOptions {
36 /// Return a new LookupOptions
37 #[cfg(feature = "dnssec")]
38 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
39 pub fn for_dnssec(is_dnssec: bool, supported_algorithms: SupportedAlgorithms) -> Self {
40 Self {
41 is_dnssec,
42 supported_algorithms,
43 }
44 }
45
46 /// Specify that this lookup should return DNSSEC related records as well, e.g. RRSIG
47 #[allow(clippy::needless_update)]
48 pub fn set_is_dnssec(self, val: bool) -> Self {
49 Self {
50 is_dnssec: val,
51 ..self
52 }
53 }
54
55 /// If true this lookup should return DNSSEC related records as well, e.g. RRSIG
56 pub fn is_dnssec(&self) -> bool {
57 self.is_dnssec
58 }
59
60 /// Specify the algorithms for which DNSSEC records should be returned
61 #[cfg(feature = "dnssec")]
62 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
63 pub fn set_supported_algorithms(self, val: SupportedAlgorithms) -> Self {
64 Self {
65 supported_algorithms: val,
66 ..self
67 }
68 }
69
70 /// The algorithms for which DNSSEC records should be returned
71 #[cfg(feature = "dnssec")]
72 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
73 pub fn supported_algorithms(&self) -> SupportedAlgorithms {
74 self.supported_algorithms
75 }
76
77 /// Returns the subset of the rrset limited to the supported_algorithms
78 pub fn rrset_with_supported_algorithms<'r>(
79 &self,
80 record_set: &'r RecordSet,
81 ) -> RrsetRecords<'r> {
82 cfg_if! {
83 if #[cfg(feature = "dnssec")] {
84 record_set.records(
85 self.is_dnssec(),
86 self.supported_algorithms(),
87 )
88 } else {
89 record_set.records_without_rrsigs()
90 }
91 }
92 }
93}
94
95/// Authority implementations can be used with a `Catalog`
96#[async_trait::async_trait]
97pub trait Authority: Send + Sync {
98 /// Result of a lookup
99 type Lookup: Send + Sync + Sized + 'static;
100
101 /// What type is this zone
102 fn zone_type(&self) -> ZoneType;
103
104 /// Return true if AXFR is allowed
105 fn is_axfr_allowed(&self) -> bool;
106
107 /// Perform a dynamic update of a zone
108 async fn update(&self, update: &MessageRequest) -> UpdateResult<bool>;
109
110 /// Get the origin of this zone, i.e. example.com is the origin for www.example.com
111 fn origin(&self) -> &LowerName;
112
113 /// Looks up all Resource Records matching the giving `Name` and `RecordType`.
114 ///
115 /// # Arguments
116 ///
117 /// * `name` - The `Name`, label, to lookup.
118 /// * `rtype` - The `RecordType`, to lookup. `RecordType::ANY` will return all records matching
119 /// `name`. `RecordType::AXFR` will return all record types except `RecordType::SOA`
120 /// due to the requirements that on zone transfers the `RecordType::SOA` must both
121 /// precede and follow all other records.
122 /// * `is_secure` - If the DO bit is set on the EDNS OPT record, then return RRSIGs as well.
123 ///
124 /// # Return value
125 ///
126 /// None if there are no matching records, otherwise a `Vec` containing the found records.
127 async fn lookup(
128 &self,
129 name: &LowerName,
130 rtype: RecordType,
131 lookup_options: LookupOptions,
132 ) -> Result<Self::Lookup, LookupError>;
133
134 /// Using the specified query, perform a lookup against this zone.
135 ///
136 /// # Arguments
137 ///
138 /// * `query` - the query to perform the lookup with.
139 /// * `is_secure` - if true, then RRSIG records (if this is a secure zone) will be returned.
140 ///
141 /// # Return value
142 ///
143 /// Returns a vector containing the results of the query, it will be empty if not found. If
144 /// `is_secure` is true, in the case of no records found then NSEC records will be returned.
145 async fn search(
146 &self,
147 request: RequestInfo<'_>,
148 lookup_options: LookupOptions,
149 ) -> Result<Self::Lookup, LookupError>;
150
151 /// Get the NS, NameServer, record for the zone
152 async fn ns(&self, lookup_options: LookupOptions) -> Result<Self::Lookup, LookupError> {
153 self.lookup(self.origin(), RecordType::NS, lookup_options)
154 .await
155 }
156
157 /// Return the NSEC records based on the given name
158 ///
159 /// # Arguments
160 ///
161 /// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
162 /// this
163 /// * `is_secure` - if true then it will return RRSIG records as well
164 async fn get_nsec_records(
165 &self,
166 name: &LowerName,
167 lookup_options: LookupOptions,
168 ) -> Result<Self::Lookup, LookupError>;
169
170 /// Returns the SOA of the authority.
171 ///
172 /// *Note*: This will only return the SOA, if this is fulfilling a request, a standard lookup
173 /// should be used, see `soa_secure()`, which will optionally return RRSIGs.
174 async fn soa(&self) -> Result<Self::Lookup, LookupError> {
175 // SOA should be origin|SOA
176 self.lookup(self.origin(), RecordType::SOA, LookupOptions::default())
177 .await
178 }
179
180 /// Returns the SOA record for the zone
181 async fn soa_secure(&self, lookup_options: LookupOptions) -> Result<Self::Lookup, LookupError> {
182 self.lookup(self.origin(), RecordType::SOA, lookup_options)
183 .await
184 }
185}
186
187/// Extension to Authority to allow for DNSSEC features
188#[cfg(feature = "dnssec")]
189#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
190#[async_trait::async_trait]
191pub trait DnssecAuthority: Authority {
192 /// Add a (Sig0) key that is authorized to perform updates against this authority
193 async fn add_update_auth_key(&self, name: Name, key: KEY) -> DnsSecResult<()>;
194
195 /// Add Signer
196 async fn add_zone_signing_key(&self, signer: SigSigner) -> DnsSecResult<()>;
197
198 /// Sign the zone for DNSSEC
199 async fn secure_zone(&self) -> DnsSecResult<()>;
200}