From 1a25fbc43549b6619fa6d6e49bfb028472018f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Christian=20Gr=C3=BCnhage?= Date: Tue, 22 Oct 2024 12:34:44 +0200 Subject: [PATCH] Reuse more hickory_proto types Fixes https://github.com/stalwartlabs/dns-update/issues/9 --- src/lib.rs | 81 +++---------------------------------- src/providers/cloudflare.rs | 63 +++++++++++++++++++++-------- src/providers/mod.rs | 12 ------ src/providers/rfc2136.rs | 62 ++-------------------------- 4 files changed, 54 insertions(+), 164 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 84799b9..2f9a881 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,12 +13,11 @@ use core::fmt; use std::{ borrow::Cow, fmt::{Display, Formatter}, - net::{Ipv4Addr, Ipv6Addr}, - str::FromStr, time::Duration, }; use hickory_client::proto::rr::dnssec::{KeyPair, Private}; +use hickory_proto::rr::RData; use providers::{ cloudflare::{CloudflareConfig, CloudflareProvider}, rfc2136::{DnsAddress, Rfc2136Config, Rfc2136Provider}, @@ -29,6 +28,8 @@ use thiserror::Error; pub mod http; pub mod providers; +pub use hickory_proto::rr::dnssec::{rdata::tsig::TsigAlgorithm, Algorithm}; + #[derive(Debug, Error)] pub enum Error { Protocol(String), @@ -41,58 +42,6 @@ pub enum Error { NotFound, } -/// A DNS record type. -pub enum DnsRecord { - A { - content: Ipv4Addr, - }, - AAAA { - content: Ipv6Addr, - }, - CNAME { - content: String, - }, - NS { - content: String, - }, - MX { - content: String, - priority: u16, - }, - TXT { - content: String, - }, - SRV { - content: String, - priority: u16, - weight: u16, - port: u16, - }, -} - -/// A TSIG algorithm. -pub enum TsigAlgorithm { - HmacMd5, - Gss, - HmacSha1, - HmacSha224, - HmacSha256, - HmacSha256_128, - HmacSha384, - HmacSha384_192, - HmacSha512, - HmacSha512_256, -} - -/// A DNSSEC algorithm. -pub enum Algorithm { - RSASHA256, - RSASHA512, - ECDSAP256SHA256, - ECDSAP384SHA384, - ED25519, -} - pub type Result = std::result::Result; #[derive(Clone, Serialize, Deserialize)] @@ -174,7 +123,7 @@ impl DnsUpdater { pub async fn create( &self, name: impl IntoFqdn<'_>, - record: DnsRecord, + record: RData, ttl: u32, origin: impl IntoFqdn<'_>, ) -> crate::Result<()> { @@ -188,7 +137,7 @@ impl DnsUpdater { pub async fn update( &self, name: impl IntoFqdn<'_>, - record: DnsRecord, + record: RData, ttl: u32, origin: impl IntoFqdn<'_>, ) -> crate::Result<()> { @@ -257,26 +206,6 @@ impl<'x> IntoFqdn<'x> for String { } } -impl FromStr for TsigAlgorithm { - type Err = (); - - fn from_str(s: &str) -> std::prelude::v1::Result { - match s { - "hmac-md5" => Ok(TsigAlgorithm::HmacMd5), - "gss" => Ok(TsigAlgorithm::Gss), - "hmac-sha1" => Ok(TsigAlgorithm::HmacSha1), - "hmac-sha224" => Ok(TsigAlgorithm::HmacSha224), - "hmac-sha256" => Ok(TsigAlgorithm::HmacSha256), - "hmac-sha256-128" => Ok(TsigAlgorithm::HmacSha256_128), - "hmac-sha384" => Ok(TsigAlgorithm::HmacSha384), - "hmac-sha384-192" => Ok(TsigAlgorithm::HmacSha384_192), - "hmac-sha512" => Ok(TsigAlgorithm::HmacSha512), - "hmac-sha512-256" => Ok(TsigAlgorithm::HmacSha512_256), - _ => Err(()), - } - } -} - impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { diff --git a/src/providers/cloudflare.rs b/src/providers/cloudflare.rs index 85b7743..e7792de 100644 --- a/src/providers/cloudflare.rs +++ b/src/providers/cloudflare.rs @@ -14,10 +14,11 @@ use std::{ time::Duration, }; +use hickory_proto::rr::RData; use serde::{Deserialize, Serialize}; use serde_json::Value; -use crate::{http::HttpClientBuilder, DnsRecord, Error, IntoFqdn}; +use crate::{http::HttpClientBuilder, Error, IntoFqdn}; #[derive(Clone, Serialize, Deserialize)] pub struct CloudflareConfig { @@ -162,7 +163,7 @@ impl CloudflareProvider { pub(crate) async fn create( &self, name: impl IntoFqdn<'_>, - record: DnsRecord, + rdata: RData, ttl: u32, origin: impl IntoFqdn<'_>, ) -> crate::Result<()> { @@ -173,10 +174,14 @@ impl CloudflareProvider { )) .with_body(CreateDnsRecordParams { ttl: ttl.into(), - priority: record.priority(), + priority: match &rdata { + RData::MX(mx) => Some(mx.preference()), + RData::SRV(srv) => Some(srv.priority()), + _ => None, + }, proxied: false.into(), name: name.into_name().as_ref(), - content: record.into(), + content: rdata.try_into()?, })? .send::>() .await @@ -187,7 +192,7 @@ impl CloudflareProvider { pub(crate) async fn update( &self, name: impl IntoFqdn<'_>, - record: DnsRecord, + rdata: RData, ttl: u32, origin: impl IntoFqdn<'_>, ) -> crate::Result<()> { @@ -202,7 +207,7 @@ impl CloudflareProvider { ttl: ttl.into(), proxied: None, name: name.as_ref(), - content: record.into(), + content: rdata.try_into()?, })? .send::>() .await @@ -252,16 +257,40 @@ impl Query { } } -impl From for DnsContent { - fn from(record: DnsRecord) -> Self { - match record { - DnsRecord::A { content } => DnsContent::A { content }, - DnsRecord::AAAA { content } => DnsContent::AAAA { content }, - DnsRecord::CNAME { content } => DnsContent::CNAME { content }, - DnsRecord::NS { content } => DnsContent::NS { content }, - DnsRecord::MX { content, priority } => DnsContent::MX { content, priority }, - DnsRecord::TXT { content } => DnsContent::TXT { content }, - DnsRecord::SRV { content, .. } => DnsContent::SRV { content }, - } +impl TryFrom for DnsContent { + type Error = crate::Error; + + fn try_from(rdata: RData) -> crate::Result { + Ok(match rdata { + RData::A(a) => DnsContent::A { content: a.0 }, + RData::AAAA(aaaa) => DnsContent::AAAA { content: aaaa.0 }, + RData::CNAME(cname) => DnsContent::CNAME { + content: cname.0.to_utf8(), + }, + RData::MX(mx) => DnsContent::MX { + content: mx.exchange().to_utf8(), + priority: mx.preference(), + }, + RData::NS(ns) => DnsContent::NS { + content: ns.0.to_utf8(), + }, + RData::SRV(srv) => DnsContent::SRV { + content: format!( + "{} {} {} {}", + srv.priority(), + srv.weight(), + srv.port(), + srv.target() + ), + }, + RData::TXT(txt) => DnsContent::TXT { + content: format!("{txt}"), + }, + rdata => { + return Err(crate::Error::Serialize(format!( + "Failed to turn record {rdata} into cloudflare DnsContent", + ))) + } + }) } } diff --git a/src/providers/mod.rs b/src/providers/mod.rs index 6ee5485..4309a9f 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -9,17 +9,5 @@ * except according to those terms. */ -use crate::DnsRecord; - pub mod cloudflare; pub mod rfc2136; - -impl DnsRecord { - pub fn priority(&self) -> Option { - match self { - DnsRecord::MX { priority, .. } => Some(*priority), - DnsRecord::SRV { priority, .. } => Some(*priority), - _ => None, - } - } -} diff --git a/src/providers/rfc2136.rs b/src/providers/rfc2136.rs index dd6eb4d..f16222d 100644 --- a/src/providers/rfc2136.rs +++ b/src/providers/rfc2136.rs @@ -23,7 +23,6 @@ use hickory_client::udp::UdpClientConnection; use hickory_proto::op::ResponseCode; use hickory_proto::rr::dnssec::rdata::tsig::TsigAlgorithm; use hickory_proto::rr::dnssec::rdata::KEY; -use hickory_proto::rr::rdata::{A, AAAA, CNAME, MX, NS, SRV, TXT}; use hickory_proto::rr::{DNSClass, Name, RData, Record}; use hickory_proto::runtime::TokioRuntimeProvider; @@ -31,7 +30,7 @@ use serde::{Deserialize, Serialize}; use serde_with::base64::Base64; use serde_with::serde_as; -use crate::{DnsRecord, Error, IntoFqdn}; +use crate::{Error, IntoFqdn}; #[derive(Clone, Serialize, Deserialize)] pub struct Rfc2136Config { @@ -161,11 +160,10 @@ impl Rfc2136Provider { pub(crate) async fn create( &self, name: impl IntoFqdn<'_>, - record: DnsRecord, + rdata: RData, ttl: u32, origin: impl IntoFqdn<'_>, ) -> crate::Result<()> { - let rdata = convert_record(record)?; let record = Record::from_rdata( Name::from_str_relaxed(name.into_name().as_ref())?, ttl, @@ -186,11 +184,10 @@ impl Rfc2136Provider { pub(crate) async fn update( &self, name: impl IntoFqdn<'_>, - record: DnsRecord, + rdata: RData, ttl: u32, origin: impl IntoFqdn<'_>, ) -> crate::Result<()> { - let rdata = convert_record(record)?; let record = Record::from_rdata( Name::from_str_relaxed(name.into_name().as_ref())?, ttl, @@ -233,30 +230,6 @@ impl Rfc2136Provider { } } -fn convert_record(record: DnsRecord) -> crate::Result { - Ok(match record { - DnsRecord::A { content } => RData::A(A::from(content)), - DnsRecord::AAAA { content } => RData::AAAA(AAAA::from(content)), - DnsRecord::CNAME { content } => RData::CNAME(CNAME(Name::from_str_relaxed(content)?)), - DnsRecord::NS { content } => RData::NS(NS(Name::from_str_relaxed(content)?)), - DnsRecord::MX { content, priority } => { - RData::MX(MX::new(priority, Name::from_str_relaxed(content)?)) - } - DnsRecord::TXT { content } => RData::TXT(TXT::new(vec![content])), - DnsRecord::SRV { - content, - priority, - weight, - port, - } => RData::SRV(SRV::new( - priority, - weight, - port, - Name::from_str_relaxed(content)?, - )), - }) -} - impl TryFrom<&str> for DnsAddress { type Error = (); @@ -310,35 +283,6 @@ impl TryFrom for DnsAddress { } } -impl From for TsigAlgorithm { - fn from(alg: crate::TsigAlgorithm) -> Self { - match alg { - crate::TsigAlgorithm::HmacMd5 => TsigAlgorithm::HmacMd5, - crate::TsigAlgorithm::Gss => TsigAlgorithm::Gss, - crate::TsigAlgorithm::HmacSha1 => TsigAlgorithm::HmacSha1, - crate::TsigAlgorithm::HmacSha224 => TsigAlgorithm::HmacSha224, - crate::TsigAlgorithm::HmacSha256 => TsigAlgorithm::HmacSha256, - crate::TsigAlgorithm::HmacSha256_128 => TsigAlgorithm::HmacSha256_128, - crate::TsigAlgorithm::HmacSha384 => TsigAlgorithm::HmacSha384, - crate::TsigAlgorithm::HmacSha384_192 => TsigAlgorithm::HmacSha384_192, - crate::TsigAlgorithm::HmacSha512 => TsigAlgorithm::HmacSha512, - crate::TsigAlgorithm::HmacSha512_256 => TsigAlgorithm::HmacSha512_256, - } - } -} - -impl From for Algorithm { - fn from(alg: crate::Algorithm) -> Self { - match alg { - crate::Algorithm::RSASHA256 => Algorithm::RSASHA256, - crate::Algorithm::RSASHA512 => Algorithm::RSASHA512, - crate::Algorithm::ECDSAP256SHA256 => Algorithm::ECDSAP256SHA256, - crate::Algorithm::ECDSAP384SHA384 => Algorithm::ECDSAP384SHA384, - crate::Algorithm::ED25519 => Algorithm::ED25519, - } - } -} - impl From for Error { fn from(e: ProtoError) -> Self { Error::Protocol(e.to_string())