Bump to dns-update 0.5.0

This commit is contained in:
Maurus Decimus
2026-05-23 19:20:25 +02:00
parent 777cf1252b
commit 4866cd331a
13 changed files with 217 additions and 138 deletions

View File

@@ -267,17 +267,22 @@ impl AcmeRequestBuilder {
.or_else(|| psl::domain_str(domain))
.unwrap_or(domain);
let proof = self.dns_proof(challenge)?;
let challenge_name = format!("_acme-challenge.{}", domain);
dns_parameters
.updater
.create(
.set_rrset(
zone,
&format!("_acme-challenge.{}", domain),
DnsRecord::TXT(self.dns_proof(challenge)?),
true,
true,
&challenge_name,
dns_update::DnsRecordType::TXT,
vec![DnsRecord::TXT(proof.clone())],
)
.await
.map_err(AcmeError::Dns)?;
dns_parameters
.updater
.wait_for_txt_propagation(&challenge_name, zone, &proof)
.await;
}
ChallengeType::DnsPersist01 => {}
ChallengeType::Unknown => unreachable!(),

View File

@@ -133,7 +133,7 @@ impl Server {
}
}
DnsRecordType::AutoConfig => {
let pacc_digest = Sha256::digest(&self.get_pacc_for_fomain(domain_name).await?);
let pacc_digest = Sha256::digest(&self.get_pacc_for_domain(domain_name).await?);
let pacc_digest_encoded = general_purpose::STANDARD.encode(pacc_digest);
records.push(NamedDnsRecord {
@@ -379,7 +379,7 @@ impl Server {
.map(|records| BindSerializer::serialize(&records))
}
pub async fn get_pacc_for_fomain(&self, domain_name: &str) -> trc::Result<String> {
pub async fn get_pacc_for_domain(&self, domain_name: &str) -> trc::Result<String> {
self.get_directory_for_domain(domain_name)
.await
.caused_by(trc::location!())

View File

@@ -1114,125 +1114,95 @@ impl DnsUpdater {
}
}
pub async fn create(
pub async fn set_rrset(
&self,
origin: &str,
name: &str,
record: DnsRecord,
verify: bool,
delete_before_create: bool,
) -> Result<bool, String> {
// First try deleting the record
if delete_before_create
&& let Err(err) = self.updater.delete(name, origin, record.as_type()).await
{
// Errors are expected if the record does not exist
trc::event!(
Dns(DnsEvent::RecordDeletionFailed),
Hostname = name.to_string(),
Reason = err.to_string(),
Details = origin.to_string(),
Type = record.as_type().as_str(),
);
}
record_type: DnsRecordType,
records: Vec<DnsRecord>,
) -> Result<(), String> {
let record_values = records
.iter()
.map(|r| trc::Value::String(r.to_string().into()))
.collect::<Vec<_>>();
// Create the record
if let Err(err) = self
.updater
.create(name, record.clone(), self.ttl.as_secs() as u32, origin)
.set_rrset(
name,
record_type,
self.ttl.as_secs() as u32,
records,
origin,
)
.await
{
return Err(format!("Failed to create DNS record: {}", err));
return Err(format!("Failed to set DNS RRSet: {}", err));
}
trc::event!(
Dns(DnsEvent::RecordCreated),
Hostname = name.to_string(),
Details = origin.to_string(),
Type = record.as_type().as_str(),
Value = record.to_string(),
Type = record_type.as_str(),
Value = record_values,
);
if verify && let DnsRecord::TXT(txt_record) = &record {
#[cfg(feature = "test_mode")]
if matches!(
self.updater,
dns_update::DnsUpdater::Pebble(_) | dns_update::DnsUpdater::InMemory(_)
) {
return Ok(true);
}
// Wait for changes to propagate
if let Some(initial_wait) = self.propagation_delay {
tokio::time::sleep(initial_wait).await;
}
let wait_until = Instant::now() + self.propagation_timeout;
let mut did_propagate = false;
while Instant::now() < wait_until {
match self.core.smtp.resolvers.dns.txt_raw_lookup(&name).await {
Ok(result) => {
let result = std::str::from_utf8(&result).unwrap_or_default();
if result.contains(txt_record) {
did_propagate = true;
break;
} else {
trc::event!(
Dns(DnsEvent::RecordNotPropagated),
Hostname = name.to_string(),
Details = origin.to_string(),
Result = result.to_string(),
Type = record.as_type().as_str(),
Value = record.to_string(),
);
}
}
Err(err) => {
trc::event!(
Dns(DnsEvent::RecordLookupFailed),
Hostname = name.to_string(),
Details = origin.to_string(),
Reason = err.to_string(),
Type = record.as_type().as_str(),
Value = record.to_string(),
);
}
}
tokio::time::sleep(self.polling_interval).await;
}
if did_propagate {
trc::event!(
Dns(DnsEvent::RecordPropagated),
Hostname = name.to_string(),
Details = origin.to_string(),
Type = record.as_type().as_str(),
Value = record.to_string(),
);
} else {
trc::event!(
Dns(DnsEvent::RecordPropagationTimeout),
Hostname = name.to_string(),
Details = origin.to_string(),
Type = record.as_type().as_str(),
Value = record.to_string(),
);
}
Ok(did_propagate)
} else {
Ok(true)
}
Ok(())
}
pub async fn delete(
pub async fn add_to_rrset(
&self,
origin: &str,
name: &str,
record_type: DnsRecordType,
records: Vec<DnsRecord>,
) -> Result<(), String> {
// First try deleting the record
match self.updater.delete(name, origin, record_type).await {
let record_values = records
.iter()
.map(|r| trc::Value::String(r.to_string().into()))
.collect::<Vec<_>>();
if let Err(err) = self
.updater
.add_to_rrset(
name,
record_type,
self.ttl.as_secs() as u32,
records,
origin,
)
.await
{
return Err(format!("Failed to add to DNS RRSet: {}", err));
}
trc::event!(
Dns(DnsEvent::RecordCreated),
Hostname = name.to_string(),
Details = origin.to_string(),
Type = record_type.as_str(),
Value = record_values,
);
Ok(())
}
pub async fn remove_from_rrset(
&self,
origin: &str,
name: &str,
record_type: DnsRecordType,
records: Vec<DnsRecord>,
) -> Result<(), String> {
let record_values = records
.iter()
.map(|r| trc::Value::String(r.to_string().into()))
.collect::<Vec<_>>();
match self
.updater
.remove_from_rrset(name, record_type, records, origin)
.await
{
Ok(_) => Ok(()),
Err(err) => {
trc::event!(
@@ -1241,11 +1211,79 @@ impl DnsUpdater {
Reason = err.to_string(),
Details = origin.to_string(),
Type = record_type.as_str(),
Value = record_values,
);
Err(err.to_string())
}
}
}
pub async fn wait_for_txt_propagation(&self, name: &str, origin: &str, expected: &str) -> bool {
#[cfg(feature = "test_mode")]
if matches!(
self.updater,
dns_update::DnsUpdater::Pebble(_) | dns_update::DnsUpdater::InMemory(_)
) {
return true;
}
if let Some(initial_wait) = self.propagation_delay {
tokio::time::sleep(initial_wait).await;
}
let wait_until = Instant::now() + self.propagation_timeout;
let mut did_propagate = false;
while Instant::now() < wait_until {
match self.core.smtp.resolvers.dns.txt_raw_lookup(&name).await {
Ok(result) => {
let result = std::str::from_utf8(&result).unwrap_or_default();
if result.contains(expected) {
did_propagate = true;
break;
} else {
trc::event!(
Dns(DnsEvent::RecordNotPropagated),
Hostname = name.to_string(),
Details = origin.to_string(),
Result = result.to_string(),
Type = DnsRecordType::TXT.as_str(),
Value = expected.to_string(),
);
}
}
Err(err) => {
trc::event!(
Dns(DnsEvent::RecordLookupFailed),
Hostname = name.to_string(),
Details = origin.to_string(),
Reason = err.to_string(),
Type = DnsRecordType::TXT.as_str(),
Value = expected.to_string(),
);
}
}
tokio::time::sleep(self.polling_interval).await;
}
if did_propagate {
trc::event!(
Dns(DnsEvent::RecordPropagated),
Hostname = name.to_string(),
Details = origin.to_string(),
Type = DnsRecordType::TXT.as_str(),
Value = expected.to_string(),
);
} else {
trc::event!(
Dns(DnsEvent::RecordPropagationTimeout),
Hostname = name.to_string(),
Details = origin.to_string(),
Type = DnsRecordType::TXT.as_str(),
Value = expected.to_string(),
);
}
did_propagate
}
}
impl Server {