From bafbe57648838d0787387417ad2e7ccf3214eb9e Mon Sep 17 00:00:00 2001 From: Thibault Cheneviere Date: Fri, 2 Aug 2024 08:58:34 -0400 Subject: [PATCH] feat: handle the delete queries and don't update a zone if no authority part is present in the query --- config.yml | 4 +- src/service/middleware/rfc2136.rs | 91 +++++++++++++++++-------------- 2 files changed, 53 insertions(+), 42 deletions(-) diff --git a/config.yml b/config.yml index 47037c7..3278422 100644 --- a/config.yml +++ b/config.yml @@ -6,9 +6,9 @@ # If not present, the values below are used as defaults. log: # The log level. This can be one of the following: trace, debug, info, warn, error, or off. - level: info + level: debug # Enable the metrics. - enable_metrics: true + enable_metrics: false # Enable thread ID in logs. enable_thread_id: false # Log on stderr. diff --git a/src/service/middleware/rfc2136.rs b/src/service/middleware/rfc2136.rs index 45e48bd..7800424 100644 --- a/src/service/middleware/rfc2136.rs +++ b/src/service/middleware/rfc2136.rs @@ -5,7 +5,7 @@ use std::marker::PhantomData; use std::sync::{Arc, Mutex}; use bytes::Bytes; -use domain::base::iana::Rcode; +use domain::base::iana::{Class, Rcode}; use domain::base::message_builder::AdditionalBuilder; use domain::base::wire::Composer; use domain::base::{Message, Name, ParsedName, Rtype, StreamTarget, ToName, Ttl}; @@ -17,7 +17,7 @@ use domain::net::server::util::mk_builder_for_target; use domain::rdata::tsig::Time48; use domain::rdata::{AllRecordData, ZoneRecordData}; use domain::tsig::{Key, ServerSequence, ServerTransaction}; -use domain::zonetree::types::{StoredRecord, StoredRecordData}; +use domain::zonetree::types::StoredRecordData; use domain::zonetree::{Answer, Rrset}; use futures::stream::Once; use futures::FutureExt; @@ -66,7 +66,6 @@ where match handle_update_query(dnsr.clone(), message_bytes) { Ok(_) => { log::info!(target: "update", "successfully updated the zone"); - log::debug!("{:?}", dnsr.zones); transaction.answer(response, Time48::now()).unwrap(); Ok(()) } @@ -112,8 +111,6 @@ where match handle_update_query(dnsr.clone(), message_bytes) { Ok(_) => { - log::info!(target: "update", "successfully updated the zone"); - log::debug!("{:?}", dnsr.zones); sequence.answer(response, Time48::now()).unwrap(); Ok(()) } @@ -226,46 +223,25 @@ fn handle_update_query( dnsr: Arc, message: Message, ) -> HandlerResult<()> { - log::debug!("handle_update_query"); - let authority = message.authority()?; - let mut records: HashMap<(Rtype, Ttl), Vec> = HashMap::new(); - - for a in authority { - let a = a?.to_record::>>()?; - - if let Some(record) = a { - let data: ZoneRecordData> = match record.data() { - AllRecordData::Txt(txt) => txt.clone().into(), - _ => unimplemented!(), - }; - - let record = StoredRecord::new( - record.owner().to_bytes(), - record.class(), - record.ttl(), - data, - ); - records - .entry((record.rtype(), record.ttl())) - .or_default() - .push(record.data().to_owned()); - } + // if there is no authority part then no update is made + if message.authority()?.next().is_none() { + log::info!(target: "update", "no authority part -- skipping zone update"); + return Ok(()); } + let authority = message.authority()?; + let records: HashMap<(Rtype, Ttl), Vec> = HashMap::new(); + let question = message.sole_question().unwrap(); - let qtype = question.qtype(); - let qname = question.qname().clone(); let records = Arc::new(Mutex::new(records)); let cloned_records = records.clone(); - let op = Box::new(move |owner: Name, rrset: &Rrset| { - if rrset.rtype() == qtype && owner == qname { - let mut records = cloned_records.lock().unwrap(); - records - .entry((rrset.rtype(), rrset.ttl())) - .or_default() - .extend(rrset.data().to_vec()); - } + let op = Box::new(move |_owner: Name, rrset: &Rrset| { + let mut records = cloned_records.lock().unwrap(); + records + .entry((rrset.rtype(), rrset.ttl())) + .or_default() + .extend(rrset.data().to_vec()); }); dnsr.zones.find_zone_walk(question.qname(), |zone| { @@ -275,7 +251,41 @@ fn handle_update_query( }); let mutex = Arc::try_unwrap(records).unwrap(); - let records = mutex.into_inner().unwrap(); + let mut records = mutex.into_inner().unwrap(); + + log::debug!("{:?}", records); + + for a in authority { + let a = a?.to_record::>>()?; + + if let Some(record) = a { + let data: ZoneRecordData> = match record.data() { + AllRecordData::Txt(txt) => txt.clone().into(), + _ => unimplemented!(), + }; + + match record.class() { + Class::IN => { + records + .entry((record.rtype(), record.ttl())) + .or_default() + .push(data); + } + Class::NONE => { + // Here we don't take ttl as a key because in delete + // queries ttl is 0 + for ((rtype, _), entry) in records.iter_mut() { + if rtype == &record.rtype() { + if let Some(index) = entry.iter().position(|r| r == &data) { + entry.remove(index); + } + } + } + } + _ => unreachable!(), + }; + } + } // TODO: handle this lot of unwraps if let Some(zone) = dnsr.zones.find_zone(&question.qname()) { @@ -293,5 +303,6 @@ fn handle_update_query( writer.commit().now_or_never().unwrap().unwrap(); } + log::info!(target: "update", "successfully updated the zone"); Ok(()) }