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}