Self check the TXT records for the given challenges.
(&self, challenges: &[Challenge])
| 360 | |
| 361 | /// Self check the TXT records for the given challenges. |
| 362 | async fn check_dns(&self, challenges: &[Challenge]) -> Result<()> { |
| 363 | use tracing::warn; |
| 364 | |
| 365 | let mut delay = Duration::from_millis(250); |
| 366 | let mut tries = 1u8; |
| 367 | |
| 368 | let mut unsettled_challenges = challenges.to_vec(); |
| 369 | |
| 370 | debug!("Unsettled challenges: {unsettled_challenges:#?}"); |
| 371 | |
| 372 | let start_time = std::time::Instant::now(); |
| 373 | |
| 374 | 'outer: loop { |
| 375 | use hickory_resolver::AsyncResolver; |
| 376 | |
| 377 | sleep(delay).await; |
| 378 | |
| 379 | let elapsed = start_time.elapsed(); |
| 380 | if elapsed >= self.max_dns_wait { |
| 381 | warn!( |
| 382 | "DNS propagation timeout after {elapsed:?}, max wait time is {max:?}. proceeding anyway as ACME server may have different DNS view", |
| 383 | max = self.max_dns_wait |
| 384 | ); |
| 385 | break; |
| 386 | } |
| 387 | |
| 388 | let dns_resolver = |
| 389 | AsyncResolver::tokio_from_system_conf().context("failed to create dns resolver")?; |
| 390 | |
| 391 | while let Some(challenge) = unsettled_challenges.pop() { |
| 392 | let expected_txt = &challenge.dns_value; |
| 393 | let settled = match dns_resolver.txt_lookup(&challenge.acme_domain).await { |
| 394 | Ok(record) => record.iter().any(|txt| { |
| 395 | let actual_txt = txt.to_string(); |
| 396 | debug!("Expected challenge: {expected_txt}, actual: {actual_txt}"); |
| 397 | actual_txt == *expected_txt |
| 398 | }), |
| 399 | Err(err) => { |
| 400 | let ResolveErrorKind::NoRecordsFound { .. } = err.kind() else { |
| 401 | bail!( |
| 402 | "failed to lookup dns record {}: {err}", |
| 403 | challenge.acme_domain |
| 404 | ); |
| 405 | }; |
| 406 | false |
| 407 | } |
| 408 | }; |
| 409 | if !settled { |
| 410 | delay = Duration::from_secs(32).min(delay * 2); |
| 411 | tries += 1; |
| 412 | debug!( |
| 413 | tries, |
| 414 | domain = &challenge.acme_domain, |
| 415 | elapsed = ?elapsed, |
| 416 | max_wait = ?self.max_dns_wait, |
| 417 | "challenge not found, waiting for {delay:?}" |
| 418 | ); |
| 419 | unsettled_challenges.push(challenge); |
no test coverage detected