hickory_server/store/sqlite/mod.rs
1// Copyright 2015-2018 Benjamin Fry <benjaminfry -@- me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! SQLite serving with Dynamic DNS and journaling support
9
10use std::{
11 ops::{Deref, DerefMut},
12 path::{Path, PathBuf},
13 sync::Arc,
14};
15
16use futures_util::lock::Mutex;
17use serde::Deserialize;
18use tracing::{error, info, warn};
19
20#[cfg(feature = "metrics")]
21use crate::store::metrics::StoreMetrics;
22use crate::{
23 authority::{
24 Authority, LookupControlFlow, LookupOptions, MessageRequest, UpdateResult, ZoneType,
25 },
26 error::{PersistenceError, PersistenceErrorKind},
27 proto::{
28 op::ResponseCode,
29 rr::{DNSClass, LowerName, Name, RData, Record, RecordSet, RecordType, RrKey},
30 },
31 server::RequestInfo,
32 store::in_memory::InMemoryAuthority,
33};
34#[cfg(feature = "__dnssec")]
35use crate::{
36 authority::{DnssecAuthority, Nsec3QueryInfo, UpdateRequest},
37 dnssec::NxProofKind,
38 proto::dnssec::{
39 DnsSecResult, SigSigner, Verifier,
40 rdata::{DNSSECRData, key::KEY},
41 },
42};
43#[cfg(feature = "__dnssec")]
44use LookupControlFlow::Continue;
45
46pub mod persistence;
47pub use persistence::Journal;
48
49/// SqliteAuthority is responsible for storing the resource records for a particular zone.
50///
51/// Authorities default to DNSClass IN. The ZoneType specifies if this should be treated as the
52/// start of authority for the zone, is a Secondary, or a cached zone.
53#[allow(dead_code)]
54pub struct SqliteAuthority {
55 in_memory: InMemoryAuthority,
56 journal: Mutex<Option<Journal>>,
57 allow_update: bool,
58 is_dnssec_enabled: bool,
59 #[cfg(feature = "metrics")]
60 metrics: StoreMetrics,
61}
62
63impl SqliteAuthority {
64 /// Creates a new Authority.
65 ///
66 /// # Arguments
67 ///
68 /// * `in_memory` - InMemoryAuthority for all records.
69 /// * `allow_update` - If true, then this zone accepts dynamic updates.
70 /// * `is_dnssec_enabled` - If true, then the zone will sign the zone with all registered keys,
71 /// (see `add_zone_signing_key()`)
72 ///
73 /// # Return value
74 ///
75 /// The new `Authority`.
76 pub fn new(in_memory: InMemoryAuthority, allow_update: bool, is_dnssec_enabled: bool) -> Self {
77 Self {
78 in_memory,
79 journal: Mutex::new(None),
80 allow_update,
81 is_dnssec_enabled,
82 #[cfg(feature = "metrics")]
83 metrics: StoreMetrics::new("sqlite"),
84 }
85 }
86
87 /// load the authority from the configuration
88 pub async fn try_from_config(
89 origin: Name,
90 zone_type: ZoneType,
91 allow_axfr: bool,
92 enable_dnssec: bool,
93 root_dir: Option<&Path>,
94 config: &SqliteConfig,
95 #[cfg(feature = "__dnssec")] nx_proof_kind: Option<NxProofKind>,
96 ) -> Result<Self, String> {
97 use crate::store::file::{FileAuthority, FileConfig};
98
99 let zone_name: Name = origin;
100
101 let root_zone_dir = root_dir.map(PathBuf::from).unwrap_or_default();
102
103 // to be compatible with previous versions, the extension might be zone, not jrnl
104 let journal_path: PathBuf = root_zone_dir.join(&config.journal_file_path);
105 let zone_path: PathBuf = root_zone_dir.join(&config.zone_file_path);
106
107 // load the zone
108 if journal_path.exists() {
109 info!("recovering zone from journal: {:?}", journal_path);
110 let journal = Journal::from_file(&journal_path)
111 .map_err(|e| format!("error opening journal: {journal_path:?}: {e}"))?;
112
113 let in_memory = InMemoryAuthority::empty(
114 zone_name.clone(),
115 zone_type,
116 allow_axfr,
117 #[cfg(feature = "__dnssec")]
118 nx_proof_kind,
119 );
120 let mut authority = Self::new(in_memory, config.allow_update, enable_dnssec);
121
122 authority
123 .recover_with_journal(&journal)
124 .await
125 .map_err(|e| format!("error recovering from journal: {e}"))?;
126
127 authority.set_journal(journal).await;
128 info!("recovered zone: {}", zone_name);
129
130 Ok(authority)
131 } else if zone_path.exists() {
132 // TODO: deprecate this portion of loading, instantiate the journal through a separate tool
133 info!("loading zone file: {:?}", zone_path);
134
135 let file_config = FileConfig {
136 zone_file_path: config.zone_file_path.clone(),
137 };
138
139 let in_memory = FileAuthority::try_from_config_internal(
140 zone_name.clone(),
141 zone_type,
142 allow_axfr,
143 root_dir,
144 &file_config,
145 #[cfg(feature = "__dnssec")]
146 nx_proof_kind,
147 #[cfg(feature = "metrics")]
148 true,
149 )?
150 .unwrap();
151
152 let mut authority = Self::new(in_memory, config.allow_update, enable_dnssec);
153
154 // if dynamic update is enabled, enable the journal
155 info!("creating new journal: {:?}", journal_path);
156 let journal = Journal::from_file(&journal_path)
157 .map_err(|e| format!("error creating journal {journal_path:?}: {e}"))?;
158
159 authority.set_journal(journal).await;
160
161 // preserve to the new journal, i.e. we just loaded the zone from disk, start the journal
162 authority
163 .persist_to_journal()
164 .await
165 .map_err(|e| format!("error persisting to journal {journal_path:?}: {e}"))?;
166
167 info!("zone file loaded: {}", zone_name);
168 Ok(authority)
169 } else {
170 Err(format!("no zone file or journal defined at: {zone_path:?}"))
171 }
172 }
173
174 /// Recovers the zone from a Journal, returns an error on failure to recover the zone.
175 ///
176 /// # Arguments
177 ///
178 /// * `journal` - the journal from which to load the persisted zone.
179 pub async fn recover_with_journal(
180 &mut self,
181 journal: &Journal,
182 ) -> Result<(), PersistenceError> {
183 assert!(
184 self.in_memory.records_get_mut().is_empty(),
185 "records should be empty during a recovery"
186 );
187
188 info!("recovering from journal");
189 for record in journal.iter() {
190 // AXFR is special, it is used to mark the dump of a full zone.
191 // when recovering, if an AXFR is encountered, we should remove all the records in the
192 // authority.
193 if record.record_type() == RecordType::AXFR {
194 self.in_memory.clear();
195 } else {
196 match self.update_records(&[record], false).await {
197 Ok(_) => {
198 #[cfg(feature = "metrics")]
199 self.metrics.persistent.zone_records.increment(1);
200 }
201 Err(error) => return Err(PersistenceErrorKind::Recovery(error.to_str()).into()),
202 }
203 }
204 }
205
206 Ok(())
207 }
208
209 /// Persist the state of the current zone to the journal, does nothing if there is no associated
210 /// Journal.
211 ///
212 /// Returns an error if there was an issue writing to the persistence layer.
213 pub async fn persist_to_journal(&self) -> Result<(), PersistenceError> {
214 if let Some(journal) = self.journal.lock().await.as_ref() {
215 let serial = self.in_memory.serial().await;
216
217 info!("persisting zone to journal at SOA.serial: {}", serial);
218
219 // TODO: THIS NEEDS TO BE IN A TRANSACTION!!!
220 journal.insert_record(
221 serial,
222 &Record::update0(Name::new(), 0, RecordType::AXFR).into_record_of_rdata(),
223 )?;
224
225 for rr_set in self.in_memory.records().await.values() {
226 // TODO: should we preserve rr_sets or not?
227 for record in rr_set.records_without_rrsigs() {
228 journal.insert_record(serial, record)?;
229
230 #[cfg(feature = "metrics")]
231 self.metrics.persistent.zone_records.increment(1);
232 }
233 }
234
235 // TODO: COMMIT THE TRANSACTION!!!
236 }
237
238 Ok(())
239 }
240
241 /// Associate a backing Journal with this Authority for Updatable zones
242 pub async fn set_journal(&mut self, journal: Journal) {
243 *self.journal.lock().await = Some(journal);
244 }
245
246 /// Returns the associated Journal
247 #[cfg(any(test, feature = "testing"))]
248 pub async fn journal(&self) -> impl Deref<Target = Option<Journal>> + '_ {
249 self.journal.lock().await
250 }
251
252 /// Enables the zone for dynamic DNS updates
253 pub fn set_allow_update(&mut self, allow_update: bool) {
254 self.allow_update = allow_update;
255 }
256
257 /// Get serial
258 #[cfg(any(test, feature = "testing"))]
259 pub async fn serial(&self) -> u32 {
260 self.in_memory.serial().await
261 }
262
263 /// [RFC 2136](https://tools.ietf.org/html/rfc2136), DNS Update, April 1997
264 ///
265 /// ```text
266 ///
267 /// 3.2 - Process Prerequisite Section
268 ///
269 /// Next, the Prerequisite Section is checked to see that all
270 /// prerequisites are satisfied by the current state of the zone. Using
271 /// the definitions expressed in Section 1.2, if any RR's NAME is not
272 /// within the zone specified in the Zone Section, signal NOTZONE to the
273 /// requestor.
274 ///
275 /// 3.2.1. For RRs in this section whose CLASS is ANY, test to see that
276 /// TTL and RDLENGTH are both zero (0), else signal FORMERR to the
277 /// requestor. If TYPE is ANY, test to see that there is at least one RR
278 /// in the zone whose NAME is the same as that of the Prerequisite RR,
279 /// else signal NXDOMAIN to the requestor. If TYPE is not ANY, test to
280 /// see that there is at least one RR in the zone whose NAME and TYPE are
281 /// the same as that of the Prerequisite RR, else signal NXRRSET to the
282 /// requestor.
283 ///
284 /// 3.2.2. For RRs in this section whose CLASS is NONE, test to see that
285 /// the TTL and RDLENGTH are both zero (0), else signal FORMERR to the
286 /// requestor. If the TYPE is ANY, test to see that there are no RRs in
287 /// the zone whose NAME is the same as that of the Prerequisite RR, else
288 /// signal YXDOMAIN to the requestor. If the TYPE is not ANY, test to
289 /// see that there are no RRs in the zone whose NAME and TYPE are the
290 /// same as that of the Prerequisite RR, else signal YXRRSET to the
291 /// requestor.
292 ///
293 /// 3.2.3. For RRs in this section whose CLASS is the same as the ZCLASS,
294 /// test to see that the TTL is zero (0), else signal FORMERR to the
295 /// requestor. Then, build an RRset for each unique <NAME,TYPE> and
296 /// compare each resulting RRset for set equality (same members, no more,
297 /// no less) with RRsets in the zone. If any Prerequisite RRset is not
298 /// entirely and exactly matched by a zone RRset, signal NXRRSET to the
299 /// requestor. If any RR in this section has a CLASS other than ZCLASS
300 /// or NONE or ANY, signal FORMERR to the requestor.
301 ///
302 /// 3.2.4 - Table Of Metavalues Used In Prerequisite Section
303 ///
304 /// CLASS TYPE RDATA Meaning
305 /// ------------------------------------------------------------
306 /// ANY ANY empty Name is in use
307 /// ANY rrset empty RRset exists (value independent)
308 /// NONE ANY empty Name is not in use
309 /// NONE rrset empty RRset does not exist
310 /// zone rrset rr RRset exists (value dependent)
311 /// ```
312 pub async fn verify_prerequisites(&self, pre_requisites: &[Record]) -> UpdateResult<()> {
313 // 3.2.5 - Pseudocode for Prerequisite Section Processing
314 //
315 // for rr in prerequisites
316 // if (rr.ttl != 0)
317 // return (FORMERR)
318 // if (zone_of(rr.name) != ZNAME)
319 // return (NOTZONE);
320 // if (rr.class == ANY)
321 // if (rr.rdlength != 0)
322 // return (FORMERR)
323 // if (rr.type == ANY)
324 // if (!zone_name<rr.name>)
325 // return (NXDOMAIN)
326 // else
327 // if (!zone_rrset<rr.name, rr.type>)
328 // return (NXRRSET)
329 // if (rr.class == NONE)
330 // if (rr.rdlength != 0)
331 // return (FORMERR)
332 // if (rr.type == ANY)
333 // if (zone_name<rr.name>)
334 // return (YXDOMAIN)
335 // else
336 // if (zone_rrset<rr.name, rr.type>)
337 // return (YXRRSET)
338 // if (rr.class == zclass)
339 // temp<rr.name, rr.type> += rr
340 // else
341 // return (FORMERR)
342 //
343 // for rrset in temp
344 // if (zone_rrset<rrset.name, rrset.type> != rrset)
345 // return (NXRRSET)
346 for require in pre_requisites {
347 let required_name = LowerName::from(require.name());
348
349 if require.ttl() != 0 {
350 warn!("ttl must be 0 for: {:?}", require);
351 return Err(ResponseCode::FormErr);
352 }
353
354 let origin = self.origin();
355 if !origin.zone_of(&require.name().into()) {
356 warn!("{} is not a zone_of {}", require.name(), origin);
357 return Err(ResponseCode::NotZone);
358 }
359
360 match require.dns_class() {
361 DNSClass::ANY => {
362 if let RData::Update0(_) | RData::NULL(..) = require.data() {
363 match require.record_type() {
364 // ANY ANY empty Name is in use
365 RecordType::ANY => {
366 if self
367 .lookup(
368 &required_name,
369 RecordType::ANY,
370 LookupOptions::default(),
371 )
372 .await
373 .unwrap_or_default()
374 .was_empty()
375 {
376 return Err(ResponseCode::NXDomain);
377 } else {
378 continue;
379 }
380 }
381 // ANY rrset empty RRset exists (value independent)
382 rrset => {
383 if self
384 .lookup(&required_name, rrset, LookupOptions::default())
385 .await
386 .unwrap_or_default()
387 .was_empty()
388 {
389 return Err(ResponseCode::NXRRSet);
390 } else {
391 continue;
392 }
393 }
394 }
395 } else {
396 return Err(ResponseCode::FormErr);
397 }
398 }
399 DNSClass::NONE => {
400 if let RData::Update0(_) | RData::NULL(..) = require.data() {
401 match require.record_type() {
402 // NONE ANY empty Name is not in use
403 RecordType::ANY => {
404 if !self
405 .lookup(
406 &required_name,
407 RecordType::ANY,
408 LookupOptions::default(),
409 )
410 .await
411 .unwrap_or_default()
412 .was_empty()
413 {
414 return Err(ResponseCode::YXDomain);
415 } else {
416 continue;
417 }
418 }
419 // NONE rrset empty RRset does not exist
420 rrset => {
421 if !self
422 .lookup(&required_name, rrset, LookupOptions::default())
423 .await
424 .unwrap_or_default()
425 .was_empty()
426 {
427 return Err(ResponseCode::YXRRSet);
428 } else {
429 continue;
430 }
431 }
432 }
433 } else {
434 return Err(ResponseCode::FormErr);
435 }
436 }
437 class if class == self.in_memory.class() =>
438 // zone rrset rr RRset exists (value dependent)
439 {
440 if !self
441 .lookup(
442 &required_name,
443 require.record_type(),
444 LookupOptions::default(),
445 )
446 .await
447 .unwrap_or_default()
448 .iter()
449 .any(|rr| rr == require)
450 {
451 return Err(ResponseCode::NXRRSet);
452 } else {
453 continue;
454 }
455 }
456 _ => return Err(ResponseCode::FormErr),
457 }
458 }
459
460 // if we didn't bail everything checked out...
461 Ok(())
462 }
463
464 /// [RFC 2136](https://tools.ietf.org/html/rfc2136), DNS Update, April 1997
465 ///
466 /// ```text
467 ///
468 /// 3.3 - Check Requestor's Permissions
469 ///
470 /// 3.3.1. Next, the requestor's permission to update the RRs named in
471 /// the Update Section may be tested in an implementation dependent
472 /// fashion or using mechanisms specified in a subsequent Secure DNS
473 /// Update protocol. If the requestor does not have permission to
474 /// perform these updates, the server may write a warning message in its
475 /// operations log, and may either signal REFUSED to the requestor, or
476 /// ignore the permission problem and proceed with the update.
477 ///
478 /// 3.3.2. While the exact processing is implementation defined, if these
479 /// verification activities are to be performed, this is the point in the
480 /// server's processing where such performance should take place, since
481 /// if a REFUSED condition is encountered after an update has been
482 /// partially applied, it will be necessary to undo the partial update
483 /// and restore the zone to its original state before answering the
484 /// requestor.
485 /// ```
486 ///
487 #[cfg(feature = "__dnssec")]
488 #[allow(clippy::blocks_in_conditions)]
489 pub async fn authorize(&self, update_message: &MessageRequest) -> UpdateResult<()> {
490 use tracing::debug;
491
492 // 3.3.3 - Pseudocode for Permission Checking
493 //
494 // if (security policy exists)
495 // if (this update is not permitted)
496 // if (local option)
497 // log a message about permission problem
498 // if (local option)
499 // return (REFUSED)
500
501 // does this authority allow_updates?
502 if !self.allow_update {
503 warn!(
504 "update attempted on non-updatable Authority: {}",
505 self.origin()
506 );
507 return Err(ResponseCode::Refused);
508 }
509
510 // verify sig0, currently the only authorization that is accepted.
511 let sig0s: &[Record] = update_message.sig0();
512 debug!("authorizing with: {:?}", sig0s);
513 if !sig0s.is_empty() {
514 let mut found_key = false;
515 for sig in sig0s
516 .iter()
517 .filter_map(|sig0| sig0.data().as_dnssec().and_then(DNSSECRData::as_sig))
518 {
519 let name = LowerName::from(sig.signer_name());
520 let keys = self
521 .lookup(&name, RecordType::KEY, LookupOptions::default())
522 .await;
523
524 let keys = match keys {
525 Continue(Ok(keys)) => keys,
526 _ => continue, // error trying to lookup a key by that name, try the next one.
527 };
528
529 debug!("found keys {:?}", keys);
530 // TODO: check key usage flags and restrictions
531 found_key = keys
532 .iter()
533 .filter_map(|rr_set| rr_set.data().as_dnssec().and_then(DNSSECRData::as_key))
534 .any(|key| {
535 key.verify_message(update_message, sig.sig(), sig)
536 .map(|_| {
537 info!("verified sig: {:?} with key: {:?}", sig, key);
538 true
539 })
540 .unwrap_or_else(|_| {
541 debug!("did not verify sig: {:?} with key: {:?}", sig, key);
542 false
543 })
544 });
545
546 if found_key {
547 break; // stop searching for matching keys, we found one
548 }
549 }
550
551 if found_key {
552 return Ok(());
553 }
554 } else {
555 warn!(
556 "no sig0 matched registered records: id {}",
557 update_message.id()
558 );
559 }
560
561 // getting here, we will always default to rejecting the request
562 // the code will only ever explicitly return authorized actions.
563 Err(ResponseCode::Refused)
564 }
565
566 /// [RFC 2136](https://tools.ietf.org/html/rfc2136), DNS Update, April 1997
567 ///
568 /// ```text
569 ///
570 /// 3.4 - Process Update Section
571 ///
572 /// Next, the Update Section is processed as follows.
573 ///
574 /// 3.4.1 - Prescan
575 ///
576 /// The Update Section is parsed into RRs and each RR's CLASS is checked
577 /// to see if it is ANY, NONE, or the same as the Zone Class, else signal
578 /// a FORMERR to the requestor. Using the definitions in Section 1.2,
579 /// each RR's NAME must be in the zone specified by the Zone Section,
580 /// else signal NOTZONE to the requestor.
581 ///
582 /// 3.4.1.2. For RRs whose CLASS is not ANY, check the TYPE and if it is
583 /// ANY, AXFR, MAILA, MAILB, or any other QUERY metatype, or any
584 /// unrecognized type, then signal FORMERR to the requestor. For RRs
585 /// whose CLASS is ANY or NONE, check the TTL to see that it is zero (0),
586 /// else signal a FORMERR to the requestor. For any RR whose CLASS is
587 /// ANY, check the RDLENGTH to make sure that it is zero (0) (that is,
588 /// the RDATA field is empty), and that the TYPE is not AXFR, MAILA,
589 /// MAILB, or any other QUERY metatype besides ANY, or any unrecognized
590 /// type, else signal FORMERR to the requestor.
591 /// ```
592 #[allow(clippy::unused_unit)]
593 pub async fn pre_scan(&self, records: &[Record]) -> UpdateResult<()> {
594 // 3.4.1.3 - Pseudocode For Update Section Prescan
595 //
596 // [rr] for rr in updates
597 // if (zone_of(rr.name) != ZNAME)
598 // return (NOTZONE);
599 // if (rr.class == zclass)
600 // if (rr.type & ANY|AXFR|MAILA|MAILB)
601 // return (FORMERR)
602 // elsif (rr.class == ANY)
603 // if (rr.ttl != 0 || rr.rdlength != 0
604 // || rr.type & AXFR|MAILA|MAILB)
605 // return (FORMERR)
606 // elsif (rr.class == NONE)
607 // if (rr.ttl != 0 || rr.type & ANY|AXFR|MAILA|MAILB)
608 // return (FORMERR)
609 // else
610 // return (FORMERR)
611 for rr in records {
612 if !self.origin().zone_of(&rr.name().into()) {
613 return Err(ResponseCode::NotZone);
614 }
615
616 let class: DNSClass = rr.dns_class();
617 if class == self.in_memory.class() {
618 match rr.record_type() {
619 RecordType::ANY | RecordType::AXFR | RecordType::IXFR => {
620 return Err(ResponseCode::FormErr);
621 }
622 _ => (),
623 }
624 } else {
625 match class {
626 DNSClass::ANY => {
627 if rr.ttl() != 0 {
628 return Err(ResponseCode::FormErr);
629 }
630 if let RData::Update0(_) | RData::NULL(..) = rr.data() {
631 ()
632 } else {
633 return Err(ResponseCode::FormErr);
634 }
635 match rr.record_type() {
636 RecordType::AXFR | RecordType::IXFR => {
637 return Err(ResponseCode::FormErr);
638 }
639 _ => (),
640 }
641 }
642 DNSClass::NONE => {
643 if rr.ttl() != 0 {
644 return Err(ResponseCode::FormErr);
645 }
646 match rr.record_type() {
647 RecordType::ANY | RecordType::AXFR | RecordType::IXFR => {
648 return Err(ResponseCode::FormErr);
649 }
650 _ => (),
651 }
652 }
653 _ => return Err(ResponseCode::FormErr),
654 }
655 }
656 }
657
658 Ok(())
659 }
660
661 /// Updates the specified records according to the update section.
662 ///
663 /// [RFC 2136](https://tools.ietf.org/html/rfc2136), DNS Update, April 1997
664 ///
665 /// ```text
666 ///
667 /// 3.4.2.6 - Table Of Metavalues Used In Update Section
668 ///
669 /// CLASS TYPE RDATA Meaning
670 /// ---------------------------------------------------------
671 /// ANY ANY empty Delete all RRsets from a name
672 /// ANY rrset empty Delete an RRset
673 /// NONE rrset rr Delete an RR from an RRset
674 /// zone rrset rr Add to an RRset
675 /// ```
676 ///
677 /// # Arguments
678 ///
679 /// * `records` - set of record instructions for update following above rules
680 /// * `auto_signing_and_increment` - if true, the zone will sign and increment the SOA, this
681 /// should be disabled during recovery.
682 pub async fn update_records(
683 &self,
684 records: &[Record],
685 auto_signing_and_increment: bool,
686 ) -> UpdateResult<bool> {
687 let mut updated = false;
688 let serial: u32 = self.in_memory.serial().await;
689
690 // the persistence act as a write-ahead log. The WAL will also be used for recovery of a zone
691 // subsequent to a failure of the server.
692 if let Some(journal) = &*self.journal.lock().await {
693 if let Err(error) = journal.insert_records(serial, records) {
694 error!("could not persist update records: {}", error);
695 return Err(ResponseCode::ServFail);
696 }
697 }
698
699 // 3.4.2.7 - Pseudocode For Update Section Processing
700 //
701 // [rr] for rr in updates
702 // if (rr.class == zclass)
703 // if (rr.type == CNAME)
704 // if (zone_rrset<rr.name, ~CNAME>)
705 // next [rr]
706 // elsif (zone_rrset<rr.name, CNAME>)
707 // next [rr]
708 // if (rr.type == SOA)
709 // if (!zone_rrset<rr.name, SOA> ||
710 // zone_rr<rr.name, SOA>.serial > rr.soa.serial)
711 // next [rr]
712 // for zrr in zone_rrset<rr.name, rr.type>
713 // if (rr.type == CNAME || rr.type == SOA ||
714 // (rr.type == WKS && rr.proto == zrr.proto &&
715 // rr.address == zrr.address) ||
716 // rr.rdata == zrr.rdata)
717 // zrr = rr
718 // next [rr]
719 // zone_rrset<rr.name, rr.type> += rr
720 // elsif (rr.class == ANY)
721 // if (rr.type == ANY)
722 // if (rr.name == zname)
723 // zone_rrset<rr.name, ~(SOA|NS)> = Nil
724 // else
725 // zone_rrset<rr.name, *> = Nil
726 // elsif (rr.name == zname &&
727 // (rr.type == SOA || rr.type == NS))
728 // next [rr]
729 // else
730 // zone_rrset<rr.name, rr.type> = Nil
731 // elsif (rr.class == NONE)
732 // if (rr.type == SOA)
733 // next [rr]
734 // if (rr.type == NS && zone_rrset<rr.name, NS> == rr)
735 // next [rr]
736 // zone_rr<rr.name, rr.type, rr.data> = Nil
737 // return (NOERROR)
738 for rr in records {
739 let rr_name = LowerName::from(rr.name());
740 let rr_key = RrKey::new(rr_name.clone(), rr.record_type());
741
742 match rr.dns_class() {
743 class if class == self.in_memory.class() => {
744 // RFC 2136 - 3.4.2.2. Any Update RR whose CLASS is the same as ZCLASS is added to
745 // the zone. In case of duplicate RDATAs (which for SOA RRs is always
746 // the case, and for WKS RRs is the case if the ADDRESS and PROTOCOL
747 // fields both match), the Zone RR is replaced by Update RR. If the
748 // TYPE is SOA and there is no Zone SOA RR, or the new SOA.SERIAL is
749 // lower (according to [RFC1982]) than or equal to the current Zone SOA
750 // RR's SOA.SERIAL, the Update RR is ignored. In the case of a CNAME
751 // Update RR and a non-CNAME Zone RRset or vice versa, ignore the CNAME
752 // Update RR, otherwise replace the CNAME Zone RR with the CNAME Update
753 // RR.
754
755 // zone rrset rr Add to an RRset
756 info!("upserting record: {:?}", rr);
757 let upserted = self.in_memory.upsert(rr.clone(), serial).await;
758
759 #[cfg(all(feature = "metrics", feature = "__dnssec"))]
760 if auto_signing_and_increment {
761 if upserted {
762 self.metrics.persistent.added();
763 } else {
764 self.metrics.persistent.updated();
765 }
766 }
767
768 updated = upserted || updated
769 }
770 DNSClass::ANY => {
771 // This is a delete of entire RRSETs, either many or one. In either case, the spec is clear:
772 match rr.record_type() {
773 t @ RecordType::SOA | t @ RecordType::NS if rr_name == *self.origin() => {
774 // SOA and NS records are not to be deleted if they are the origin records
775 info!("skipping delete of {:?} see RFC 2136 - 3.4.2.3", t);
776 continue;
777 }
778 RecordType::ANY => {
779 // RFC 2136 - 3.4.2.3. For any Update RR whose CLASS is ANY and whose TYPE is ANY,
780 // all Zone RRs with the same NAME are deleted, unless the NAME is the
781 // same as ZNAME in which case only those RRs whose TYPE is other than
782 // SOA or NS are deleted.
783
784 // ANY ANY empty Delete all RRsets from a name
785 info!(
786 "deleting all records at name (not SOA or NS at origin): {:?}",
787 rr_name
788 );
789 let origin = self.origin();
790 let to_delete = self
791 .in_memory
792 .records()
793 .await
794 .keys()
795 .filter(|k| {
796 !((k.record_type == RecordType::SOA
797 || k.record_type == RecordType::NS)
798 && k.name != *origin)
799 })
800 .filter(|k| k.name == rr_name)
801 .cloned()
802 .collect::<Vec<RrKey>>();
803
804 for delete in to_delete {
805 self.in_memory.records_mut().await.remove(&delete);
806 updated = true;
807
808 #[cfg(all(feature = "metrics", feature = "__dnssec"))]
809 if auto_signing_and_increment {
810 self.metrics.persistent.deleted()
811 }
812 }
813 }
814 _ => {
815 // RFC 2136 - 3.4.2.3. For any Update RR whose CLASS is ANY and
816 // whose TYPE is not ANY all Zone RRs with the same NAME and TYPE are
817 // deleted, unless the NAME is the same as ZNAME in which case neither
818 // SOA or NS RRs will be deleted.
819
820 // ANY rrset empty Delete an RRset
821 if let RData::Update0(_) | RData::NULL(..) = rr.data() {
822 let deleted = self.in_memory.records_mut().await.remove(&rr_key);
823 info!("deleted rrset: {:?}", deleted);
824 updated = updated || deleted.is_some();
825
826 #[cfg(all(feature = "metrics", feature = "__dnssec"))]
827 if auto_signing_and_increment {
828 self.metrics.persistent.deleted()
829 }
830 } else {
831 info!("expected empty rdata: {:?}", rr);
832 return Err(ResponseCode::FormErr);
833 }
834 }
835 }
836 }
837 DNSClass::NONE => {
838 info!("deleting specific record: {:?}", rr);
839 // NONE rrset rr Delete an RR from an RRset
840 if let Some(rrset) = self.in_memory.records_mut().await.get_mut(&rr_key) {
841 // b/c this is an Arc, we need to clone, then remove, and replace the node.
842 let mut rrset_clone: RecordSet = RecordSet::clone(&*rrset);
843 let deleted = rrset_clone.remove(rr, serial);
844 info!("deleted ({}) specific record: {:?}", deleted, rr);
845 updated = updated || deleted;
846
847 if deleted {
848 *rrset = Arc::new(rrset_clone);
849 }
850
851 #[cfg(all(feature = "metrics", feature = "__dnssec"))]
852 if auto_signing_and_increment {
853 self.metrics.persistent.deleted()
854 }
855 }
856 }
857 class => {
858 info!("unexpected DNS Class: {:?}", class);
859 return Err(ResponseCode::FormErr);
860 }
861 }
862 }
863
864 // update the serial...
865 if updated && auto_signing_and_increment {
866 if self.is_dnssec_enabled {
867 cfg_if::cfg_if! {
868 if #[cfg(feature = "__dnssec")] {
869 self.secure_zone().await.map_err(|e| {
870 error!("failure securing zone: {}", e);
871 ResponseCode::ServFail
872 })?
873 } else {
874 error!("failure securing zone, dnssec feature not enabled");
875 return Err(ResponseCode::ServFail)
876 }
877 }
878 } else {
879 // the secure_zone() function increments the SOA during it's operation, if we're not
880 // dnssec, then we need to do it here...
881 self.in_memory.increment_soa_serial().await;
882 }
883 }
884
885 Ok(updated)
886 }
887}
888
889impl Deref for SqliteAuthority {
890 type Target = InMemoryAuthority;
891
892 fn deref(&self) -> &Self::Target {
893 &self.in_memory
894 }
895}
896
897impl DerefMut for SqliteAuthority {
898 fn deref_mut(&mut self) -> &mut Self::Target {
899 &mut self.in_memory
900 }
901}
902
903#[async_trait::async_trait]
904impl Authority for SqliteAuthority {
905 type Lookup = <InMemoryAuthority as Authority>::Lookup;
906
907 /// What type is this zone
908 fn zone_type(&self) -> ZoneType {
909 self.in_memory.zone_type()
910 }
911
912 /// Return true if AXFR is allowed
913 fn is_axfr_allowed(&self) -> bool {
914 self.in_memory.is_axfr_allowed()
915 }
916
917 /// Takes the UpdateMessage, extracts the Records, and applies the changes to the record set.
918 ///
919 /// [RFC 2136](https://tools.ietf.org/html/rfc2136), DNS Update, April 1997
920 ///
921 /// ```text
922 ///
923 /// 3.4 - Process Update Section
924 ///
925 /// Next, the Update Section is processed as follows.
926 ///
927 /// 3.4.2 - Update
928 ///
929 /// The Update Section is parsed into RRs and these RRs are processed in
930 /// order.
931 ///
932 /// 3.4.2.1. If any system failure (such as an out of memory condition,
933 /// or a hardware error in persistent storage) occurs during the
934 /// processing of this section, signal SERVFAIL to the requestor and undo
935 /// all updates applied to the zone during this transaction.
936 ///
937 /// 3.4.2.2. Any Update RR whose CLASS is the same as ZCLASS is added to
938 /// the zone. In case of duplicate RDATAs (which for SOA RRs is always
939 /// the case, and for WKS RRs is the case if the ADDRESS and PROTOCOL
940 /// fields both match), the Zone RR is replaced by Update RR. If the
941 /// TYPE is SOA and there is no Zone SOA RR, or the new SOA.SERIAL is
942 /// lower (according to [RFC1982]) than or equal to the current Zone SOA
943 /// RR's SOA.SERIAL, the Update RR is ignored. In the case of a CNAME
944 /// Update RR and a non-CNAME Zone RRset or vice versa, ignore the CNAME
945 /// Update RR, otherwise replace the CNAME Zone RR with the CNAME Update
946 /// RR.
947 ///
948 /// 3.4.2.3. For any Update RR whose CLASS is ANY and whose TYPE is ANY,
949 /// all Zone RRs with the same NAME are deleted, unless the NAME is the
950 /// same as ZNAME in which case only those RRs whose TYPE is other than
951 /// SOA or NS are deleted. For any Update RR whose CLASS is ANY and
952 /// whose TYPE is not ANY all Zone RRs with the same NAME and TYPE are
953 /// deleted, unless the NAME is the same as ZNAME in which case neither
954 /// SOA or NS RRs will be deleted.
955 ///
956 /// 3.4.2.4. For any Update RR whose class is NONE, any Zone RR whose
957 /// NAME, TYPE, RDATA and RDLENGTH are equal to the Update RR is deleted,
958 /// unless the NAME is the same as ZNAME and either the TYPE is SOA or
959 /// the TYPE is NS and the matching Zone RR is the only NS remaining in
960 /// the RRset, in which case this Update RR is ignored.
961 ///
962 /// 3.4.2.5. Signal NOERROR to the requestor.
963 /// ```
964 ///
965 /// # Arguments
966 ///
967 /// * `update` - The `UpdateMessage` records will be extracted and used to perform the update
968 /// actions as specified in the above RFC.
969 ///
970 /// # Return value
971 ///
972 /// true if any of additions, updates or deletes were made to the zone, false otherwise. Err is
973 /// returned in the case of bad data, etc.
974 #[cfg(feature = "__dnssec")]
975 async fn update(&self, update: &MessageRequest) -> UpdateResult<bool> {
976 //let this = &mut self.in_memory.lock().await;
977 // the spec says to authorize after prereqs, seems better to auth first.
978 self.authorize(update).await?;
979 self.verify_prerequisites(update.prerequisites()).await?;
980 self.pre_scan(update.updates()).await?;
981
982 self.update_records(update.updates(), true).await
983 }
984
985 /// Always fail when DNSSEC is disabled.
986 #[cfg(not(feature = "__dnssec"))]
987 async fn update(&self, _update: &MessageRequest) -> UpdateResult<bool> {
988 Err(ResponseCode::NotImp)
989 }
990
991 /// Get the origin of this zone, i.e. example.com is the origin for www.example.com
992 fn origin(&self) -> &LowerName {
993 self.in_memory.origin()
994 }
995
996 /// Looks up all Resource Records matching the given `Name` and `RecordType`.
997 ///
998 /// # Arguments
999 ///
1000 /// * `name` - The name to look up.
1001 /// * `rtype` - The `RecordType` to look up. `RecordType::ANY` will return all records matching
1002 /// `name`. `RecordType::AXFR` will return all record types except `RecordType::SOA`
1003 /// due to the requirements that on zone transfers the `RecordType::SOA` must both
1004 /// precede and follow all other records.
1005 /// * `lookup_options` - Query-related lookup options (e.g., DNSSEC DO bit, supported hash
1006 /// algorithms, etc.)
1007 ///
1008 /// # Return value
1009 ///
1010 /// A LookupControlFlow containing the lookup that should be returned to the client.
1011 async fn lookup(
1012 &self,
1013 name: &LowerName,
1014 rtype: RecordType,
1015 lookup_options: LookupOptions,
1016 ) -> LookupControlFlow<Self::Lookup> {
1017 let lookup = self.in_memory.lookup(name, rtype, lookup_options).await;
1018
1019 #[cfg(feature = "metrics")]
1020 self.metrics.query.increment_lookup(&lookup);
1021
1022 lookup
1023 }
1024
1025 async fn search(
1026 &self,
1027 request_info: RequestInfo<'_>,
1028 lookup_options: LookupOptions,
1029 ) -> LookupControlFlow<Self::Lookup> {
1030 let search = self.in_memory.search(request_info, lookup_options).await;
1031
1032 #[cfg(feature = "metrics")]
1033 self.metrics.query.increment_lookup(&search);
1034
1035 search
1036 }
1037
1038 /// Return the NSEC records based on the given name
1039 ///
1040 /// # Arguments
1041 ///
1042 /// * `name` - given this name (i.e. the lookup name), return the NSEC record that is less than
1043 /// this
1044 /// * `lookup_options` - Query-related lookup options (e.g., DNSSEC DO bit, supported hash
1045 /// algorithms, etc.)
1046 async fn get_nsec_records(
1047 &self,
1048 name: &LowerName,
1049 lookup_options: LookupOptions,
1050 ) -> LookupControlFlow<Self::Lookup> {
1051 self.in_memory.get_nsec_records(name, lookup_options).await
1052 }
1053
1054 #[cfg(feature = "__dnssec")]
1055 async fn get_nsec3_records(
1056 &self,
1057 info: Nsec3QueryInfo<'_>,
1058 lookup_options: LookupOptions,
1059 ) -> LookupControlFlow<Self::Lookup> {
1060 self.in_memory.get_nsec3_records(info, lookup_options).await
1061 }
1062
1063 #[cfg(feature = "__dnssec")]
1064 fn nx_proof_kind(&self) -> Option<&NxProofKind> {
1065 self.in_memory.nx_proof_kind()
1066 }
1067}
1068
1069#[cfg(feature = "__dnssec")]
1070#[async_trait::async_trait]
1071impl DnssecAuthority for SqliteAuthority {
1072 async fn add_update_auth_key(&self, name: Name, key: KEY) -> DnsSecResult<()> {
1073 self.in_memory.add_update_auth_key(name, key).await
1074 }
1075
1076 /// By adding a secure key, this will implicitly enable dnssec for the zone.
1077 ///
1078 /// # Arguments
1079 ///
1080 /// * `signer` - Signer with associated private key
1081 async fn add_zone_signing_key(&self, signer: SigSigner) -> DnsSecResult<()> {
1082 self.in_memory.add_zone_signing_key(signer).await
1083 }
1084
1085 /// (Re)generates the nsec records, increments the serial number and signs the zone
1086 async fn secure_zone(&self) -> DnsSecResult<()> {
1087 self.in_memory.secure_zone().await
1088 }
1089}
1090
1091/// Configuration for zone file for sqlite based zones
1092#[derive(Deserialize, PartialEq, Eq, Debug)]
1093#[serde(deny_unknown_fields)]
1094pub struct SqliteConfig {
1095 /// path to initial zone file
1096 pub zone_file_path: PathBuf,
1097 /// path to the sqlite journal file
1098 pub journal_file_path: String,
1099 /// Are updates allowed to this zone
1100 #[serde(default)]
1101 pub allow_update: bool,
1102}
1103
1104#[cfg(test)]
1105#[allow(clippy::extra_unused_type_parameters)]
1106mod tests {
1107 use crate::store::sqlite::SqliteAuthority;
1108
1109 #[test]
1110 fn test_is_send_sync() {
1111 fn send_sync<T: Send + Sync>() -> bool {
1112 true
1113 }
1114
1115 assert!(send_sync::<SqliteAuthority>());
1116 }
1117}