ferron_common/
dns.rs

1use std::error::Error;
2
3use async_trait::async_trait;
4use hickory_resolver::{config::ResolverConfig, name_server::TokioConnectionProvider};
5
6/// Trait for DNS providers used for DNS-01 ACME challenge.
7#[async_trait]
8pub trait DnsProvider {
9  async fn set_acme_txt_record(
10    &self,
11    acme_challenge_identifier: &str,
12    dns_value: &str,
13  ) -> Result<(), Box<dyn Error + Send + Sync>>;
14
15  #[allow(unused_variables)]
16  async fn remove_acme_txt_record(&self, acme_challenge_identifier: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
17    Ok(())
18  }
19}
20
21/// Separates subdomain from domain name.
22pub async fn separate_subdomain_from_domain_name(domain_name: &str) -> (String, String) {
23  let parts: Vec<&str> = domain_name
24    .strip_suffix(".")
25    .unwrap_or(domain_name)
26    .split('.')
27    .collect();
28  let resolver = hickory_resolver::Resolver::builder_tokio()
29    .unwrap_or(hickory_resolver::Resolver::builder_with_config(
30      ResolverConfig::default(),
31      TokioConnectionProvider::default(),
32    ))
33    .build();
34
35  for parts_index in 0..parts.len() {
36    if resolver
37      .soa_lookup(format!("{}.", parts[parts_index..].join(".")))
38      .await
39      .is_ok()
40    {
41      // SOA record found
42      let subdomain = parts[..parts_index].join(".");
43      let domain = parts[parts_index..].join(".");
44      return (subdomain, domain);
45    }
46  }
47
48  ("".to_string(), parts.join("."))
49}