Split resolving and decoding

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2023-02-09 12:12:09 +01:00
parent 2c00e57bc6
commit fd76ec9983
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
3 changed files with 51 additions and 38 deletions

View File

@ -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<Record> {
pub async fn resolv(&self, domain: &str) -> ::std::io::Result<String> {
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();
return Ok(txt);
}
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<Record> {
if !txt.starts_with(Self::TXT_RECORD_START) {
return Err(::std::io::Error::new(
::std::io::ErrorKind::InvalidData,
"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);
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 Err(if found_but_wrong {
::std::io::Error::new(
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",
)
});
"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",
))
}
};
}
}

View File

@ -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 {

View File

@ -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<UdpSocket>, 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<dnssec::Record, Error> {
pub async fn resolv_str(&self, domain: &str) -> Result<String, Error> {
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<dnssec::Record, Error> {
let record_str = self.resolv_str(domain).await?;
Ok(dnssec::Dnssec::parse_txt_record(&record_str)?)
}
}
/// Add an async udp listener