From fd76ec99835a31c8f5084a264d4b13341d5eceec Mon Sep 17 00:00:00 2001 From: Luca Fulchir Date: Thu, 9 Feb 2023 12:12:09 +0100 Subject: [PATCH] Split resolving and decoding Signed-off-by: Luca Fulchir --- src/dnssec/mod.rs | 69 ++++++++++++++++++++++++-------------------- src/dnssec/record.rs | 4 +-- src/lib.rs | 16 ++++++---- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/dnssec/mod.rs b/src/dnssec/mod.rs index 0d28d8b..912321d 100644 --- a/src/dnssec/mod.rs +++ b/src/dnssec/mod.rs @@ -86,51 +86,58 @@ impl Dnssec { Ok(Self { resolver }) } + const TXT_RECORD_START: &str = "v=Fenrir1 "; /// Get the fenrir data for a domain - pub async fn resolv(&self, domain: &str) -> ::std::io::Result { + pub async fn resolv(&self, domain: &str) -> ::std::io::Result { use ::trust_dns_client::rr::Name; let fqdn_str = "_fenrir.".to_owned() + domain; ::tracing::debug!("Resolving: {}", fqdn_str); let fqdn = Name::from_utf8(&fqdn_str)?; let answers = self.resolver.txt_lookup(fqdn).await?; - const TXT_RECORD_START: &str = "v=Fenrir1 "; - let mut found_but_wrong: bool = false; for txt_raw in answers.into_iter() { let txt = ::std::format!("{}", txt_raw); - if !txt.starts_with(TXT_RECORD_START) { + if !txt.starts_with(Self::TXT_RECORD_START) { ::tracing::trace!("Found NON-fenrir record: {}", txt); continue; } ::tracing::trace!("Found fenrir record: {}", txt); - let base85 = txt[TXT_RECORD_START.len()..].trim(); - let bytes = match ::base85::decode(base85) { - Ok(bytes) => bytes, - Err(e) => { - ::tracing::error!("Invalid DNSSEC base85: {}", e); - continue; - } - }; - let record = match Record::decode(&bytes) { - Ok(record) => record, - Err(e) => { - found_but_wrong = true; - ::tracing::error!("{}: {}", fqdn_str, e); - continue; - } - }; - return Ok(record); + return Ok(txt); } - return Err(if found_but_wrong { - ::std::io::Error::new( + Err(::std::io::Error::new( + ::std::io::ErrorKind::NotFound, + "record not found", + )) + } + /// Parse the dns TXT record and output a `Record` struct + pub fn parse_txt_record(txt: &str) -> ::std::io::Result { + if !txt.starts_with(Self::TXT_RECORD_START) { + return Err(::std::io::Error::new( ::std::io::ErrorKind::InvalidData, - "record found but not parsable", - ) - } else { - ::std::io::Error::new( - ::std::io::ErrorKind::NotFound, - "record not found", - ) - }); + "Self::TXT record does not start with \"v=Fenrir1\"", + )); + } + + let base85 = txt[Self::TXT_RECORD_START.len()..].trim(); + let bytes = match ::base85::decode(base85) { + Ok(bytes) => bytes, + Err(e) => { + ::tracing::error!("Invalid DNSSEC base85: {}", e); + return Err(::std::io::Error::new( + ::std::io::ErrorKind::InvalidData, + "record is not base85, RFC1924", + )); + } + }; + return match Record::decode(&bytes) { + Ok(record) => Ok(record), + Err(e) => { + ::tracing::error!("Can't parse record: {}", e); + Err(::std::io::Error::new( + ::std::io::ErrorKind::InvalidData, + "Can't parse the record", + )) + } + }; } } diff --git a/src/dnssec/record.rs b/src/dnssec/record.rs index 5492621..cc63417 100644 --- a/src/dnssec/record.rs +++ b/src/dnssec/record.rs @@ -63,7 +63,7 @@ impl PublicKeyType { /// Get the size of a public key of this kind pub fn key_len(&self) -> usize { match &self { - PublicKeyType::Ed25519 => 42, + PublicKeyType::Ed25519 => 32, } } } @@ -314,7 +314,7 @@ impl Address { let public_key_id = PublicKeyId(raw[1]); - let raw_port = u16::from_le_bytes(raw[2..3].try_into().unwrap()); + let raw_port = u16::from_le_bytes([raw[2], raw[3]]); let port = if raw_port == 0 { None } else { diff --git a/src/lib.rs b/src/lib.rs index ea22a8b..368b431 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,10 +80,11 @@ impl Fenrir { /// Stop all workers, listeners /// asyncronous version for Drop fn stop_sync(&mut self) { + let _ = self.stop_working.send(true); let mut toempty_socket = Vec::new(); ::std::mem::swap(&mut self.sockets, &mut toempty_socket); - let task = ::tokio::task::spawn(Self::real_stop(toempty_socket)); - let _ = futures::executor::block_on(task); + let task = ::tokio::task::spawn(Self::stop_sockets(toempty_socket)); + let _ = ::futures::executor::block_on(task); self.dnssec = None; } /// Stop all workers, listeners @@ -91,11 +92,11 @@ impl Fenrir { let _ = self.stop_working.send(true); let mut toempty_socket = Vec::new(); ::std::mem::swap(&mut self.sockets, &mut toempty_socket); - Self::real_stop(toempty_socket).await; + Self::stop_sockets(toempty_socket).await; self.dnssec = None; } /// actually do the work of stopping resolvers and listeners - async fn real_stop( + async fn stop_sockets( sockets: Vec<(Arc, JoinHandle<::std::io::Result<()>>)>, ) { for s in sockets.into_iter() { @@ -126,12 +127,17 @@ impl Fenrir { Ok(()) } /// Get the raw TXT record of a Fenrir domain - pub async fn resolv(&self, domain: &str) -> Result { + pub async fn resolv_str(&self, domain: &str) -> Result { match &self.dnssec { Some(dnssec) => Ok(dnssec.resolv(domain).await?), None => Err(Error::NotInitialized), } } + /// Get the raw TXT record of a Fenrir domain + pub async fn resolv(&self, domain: &str) -> Result { + let record_str = self.resolv_str(domain).await?; + Ok(dnssec::Dnssec::parse_txt_record(&record_str)?) + } } /// Add an async udp listener