Skip to main content

dns_update/
update.rs

1/*
2 * Copyright Stalwart Labs LLC See the COPYING
3 * file at the top-level directory of this distribution.
4 *
5 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8 * option. This file may not be copied, modified, or distributed
9 * except according to those terms.
10 */
11
12#[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
13use crate::providers::ovh::{OvhEndpoint, OvhProvider};
14
15#[cfg(feature = "test_provider")]
16use crate::providers::{in_memory::InMemoryProvider, pebble::PebbleProvider};
17
18#[cfg(feature = "test_provider")]
19use crate::NamedDnsRecord;
20
21#[cfg(feature = "test_provider")]
22use std::sync::{Arc, Mutex};
23
24use crate::{
25    DnsRecord, DnsRecordType, DnsUpdater, IntoFqdn, TsigAlgorithm,
26    providers::{
27        bunny::BunnyProvider,
28        cloudflare::CloudflareProvider,
29        desec::DesecProvider,
30        digitalocean::DigitalOceanProvider,
31        dnsimple::DNSimpleProvider,
32        porkbun::PorkBunProvider,
33        rfc2136::{DnsAddress, Rfc2136Provider},
34        route53::Route53Provider,
35        spaceship::SpaceshipProvider,
36    },
37};
38use std::time::Duration;
39
40impl DnsUpdater {
41    /// Create a new DNS updater using the RFC 2136 protocol and TSIG authentication.
42    pub fn new_rfc2136_tsig(
43        addr: impl TryInto<DnsAddress>,
44        key_name: impl AsRef<str>,
45        key: impl Into<Vec<u8>>,
46        algorithm: TsigAlgorithm,
47    ) -> crate::Result<Self> {
48        Ok(DnsUpdater::Rfc2136(Rfc2136Provider::new_tsig(
49            addr,
50            key_name,
51            key,
52            algorithm.into(),
53        )?))
54    }
55
56    /// Create a new DNS updater using the Cloudflare API.
57    pub fn new_cloudflare(
58        secret: impl AsRef<str>,
59        email: Option<impl AsRef<str>>,
60        timeout: Option<Duration>,
61    ) -> crate::Result<Self> {
62        Ok(DnsUpdater::Cloudflare(CloudflareProvider::new(
63            secret, email, timeout,
64        )?))
65    }
66
67    /// Create a new DNS updater using the Cloudflare API.
68    pub fn new_digitalocean(
69        auth_token: impl AsRef<str>,
70        timeout: Option<Duration>,
71    ) -> crate::Result<Self> {
72        Ok(DnsUpdater::DigitalOcean(DigitalOceanProvider::new(
73            auth_token, timeout,
74        )))
75    }
76
77    /// Create a new DNS updater using the Desec.io API.
78    pub fn new_desec(
79        auth_token: impl AsRef<str>,
80        timeout: Option<Duration>,
81    ) -> crate::Result<Self> {
82        Ok(DnsUpdater::Desec(DesecProvider::new(auth_token, timeout)))
83    }
84
85    /// Create a new DNS updater using the OVH API.
86    #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
87    pub fn new_ovh(
88        application_key: impl AsRef<str>,
89        application_secret: impl AsRef<str>,
90        consumer_key: impl AsRef<str>,
91        endpoint: OvhEndpoint,
92        timeout: Option<Duration>,
93    ) -> crate::Result<Self> {
94        Ok(DnsUpdater::Ovh(OvhProvider::new(
95            application_key,
96            application_secret,
97            consumer_key,
98            endpoint,
99            timeout,
100        )?))
101    }
102
103    /// Create a new DNS updater using the Bunny API.
104    pub fn new_bunny(api_key: impl AsRef<str>, timeout: Option<Duration>) -> crate::Result<Self> {
105        Ok(DnsUpdater::Bunny(BunnyProvider::new(api_key, timeout)?))
106    }
107
108    /// Create a new DNS updater using the Porkbun API.
109    pub fn new_porkbun(
110        api_key: impl AsRef<str>,
111        secret_api_key: impl AsRef<str>,
112        timeout: Option<Duration>,
113    ) -> crate::Result<Self> {
114        Ok(DnsUpdater::Porkbun(PorkBunProvider::new(
115            api_key,
116            secret_api_key,
117            timeout,
118        )))
119    }
120
121    /// Create a new DNS updater using the Spaceship API.
122    pub fn new_spaceship(
123        api_key: impl AsRef<str>,
124        api_secret: impl AsRef<str>,
125        timeout: Option<Duration>,
126    ) -> crate::Result<Self> {
127        Ok(DnsUpdater::Spaceship(SpaceshipProvider::new(
128            api_key, api_secret, timeout,
129        )))
130    }
131
132    /// Create a new DNS updater using the DNSimple API.
133    pub fn new_dnsimple(
134        auth_token: impl AsRef<str>,
135        account_id: impl AsRef<str>,
136        timeout: Option<Duration>,
137    ) -> crate::Result<Self> {
138        Ok(DnsUpdater::DNSimple(DNSimpleProvider::new(
139            auth_token, account_id, timeout,
140        )))
141    }
142
143    /// Create a new DNS updater using the Google Cloud DNS API.
144    pub fn new_google_cloud_dns(
145        config: crate::providers::google_cloud_dns::GoogleCloudDnsConfig,
146    ) -> crate::Result<Self> {
147        Ok(DnsUpdater::GoogleCloudDns(
148            crate::providers::google_cloud_dns::GoogleCloudDnsProvider::new(config)?,
149        ))
150    }
151
152    /// Create a new DNS updater using the Route53 API.
153    pub fn new_route53(config: crate::providers::route53::Route53Config) -> crate::Result<Self> {
154        Ok(DnsUpdater::Route53(Route53Provider::new(config)))
155    }
156
157    /// Create a new DNS updater using the Pebble Challenge Test Server.
158    #[cfg(feature = "test_provider")]
159    pub fn new_pebble(base_url: impl AsRef<str>, timeout: Option<Duration>) -> Self {
160        DnsUpdater::Pebble(PebbleProvider::new(base_url, timeout))
161    }
162
163    /// Create a new DNS updater backed by an in-memory record store.
164    #[cfg(feature = "test_provider")]
165    pub fn new_in_memory(records: Arc<Mutex<Vec<NamedDnsRecord>>>) -> Self {
166        DnsUpdater::InMemory(InMemoryProvider::new(records))
167    }
168
169    /// Create a new DNS record.
170    pub async fn create(
171        &self,
172        name: impl IntoFqdn<'_>,
173        record: DnsRecord,
174        ttl: u32,
175        origin: impl IntoFqdn<'_>,
176    ) -> crate::Result<()> {
177        match self {
178            DnsUpdater::Bunny(provider) => provider.create(name, record, ttl, origin).await,
179            DnsUpdater::Cloudflare(provider) => provider.create(name, record, ttl, origin).await,
180            DnsUpdater::Desec(provider) => provider.create(name, record, ttl, origin).await,
181            DnsUpdater::DigitalOcean(provider) => provider.create(name, record, ttl, origin).await,
182            DnsUpdater::DNSimple(provider) => provider.create(name, record, ttl, origin).await,
183            #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
184            DnsUpdater::Ovh(provider) => provider.create(name, record, ttl, origin).await,
185            DnsUpdater::Porkbun(provider) => provider.create(name, record, ttl, origin).await,
186            DnsUpdater::Rfc2136(provider) => provider.create(name, record, ttl, origin).await,
187            DnsUpdater::Route53(provider) => provider.create(name, record, ttl, origin).await,
188            DnsUpdater::Spaceship(provider) => provider.create(name, record, ttl, origin).await,
189            DnsUpdater::GoogleCloudDns(provider) => {
190                provider.create(name, record, ttl, origin).await
191            }
192            #[cfg(feature = "test_provider")]
193            DnsUpdater::Pebble(provider) => provider.create(name, record, ttl, origin).await,
194            #[cfg(feature = "test_provider")]
195            DnsUpdater::InMemory(provider) => provider.create(name, record, ttl, origin).await,
196        }
197    }
198
199    /// Update an existing DNS record.
200    pub async fn update(
201        &self,
202        name: impl IntoFqdn<'_>,
203        record: DnsRecord,
204        ttl: u32,
205        origin: impl IntoFqdn<'_>,
206    ) -> crate::Result<()> {
207        match self {
208            DnsUpdater::Bunny(provider) => provider.update(name, record, ttl, origin).await,
209            DnsUpdater::Cloudflare(provider) => provider.update(name, record, ttl, origin).await,
210            DnsUpdater::Desec(provider) => provider.update(name, record, ttl, origin).await,
211            DnsUpdater::DigitalOcean(provider) => provider.update(name, record, ttl, origin).await,
212            DnsUpdater::DNSimple(provider) => provider.update(name, record, ttl, origin).await,
213            #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
214            DnsUpdater::Ovh(provider) => provider.update(name, record, ttl, origin).await,
215            DnsUpdater::Porkbun(provider) => provider.update(name, record, ttl, origin).await,
216            DnsUpdater::Rfc2136(provider) => provider.update(name, record, ttl, origin).await,
217            DnsUpdater::Route53(provider) => provider.update(name, record, ttl, origin).await,
218            DnsUpdater::Spaceship(provider) => provider.update(name, record, ttl, origin).await,
219            DnsUpdater::GoogleCloudDns(provider) => {
220                provider.update(name, record, ttl, origin).await
221            }
222            #[cfg(feature = "test_provider")]
223            DnsUpdater::Pebble(provider) => provider.update(name, record, ttl, origin).await,
224            #[cfg(feature = "test_provider")]
225            DnsUpdater::InMemory(provider) => provider.update(name, record, ttl, origin).await,
226        }
227    }
228
229    /// Delete an existing DNS record.
230    pub async fn delete(
231        &self,
232        name: impl IntoFqdn<'_>,
233        origin: impl IntoFqdn<'_>,
234        record: DnsRecordType,
235    ) -> crate::Result<()> {
236        match self {
237            DnsUpdater::Bunny(provider) => provider.delete(name, origin, record).await,
238            DnsUpdater::Cloudflare(provider) => provider.delete(name, origin, record).await,
239            DnsUpdater::Desec(provider) => provider.delete(name, origin, record).await,
240            DnsUpdater::DigitalOcean(provider) => provider.delete(name, origin, record).await,
241            DnsUpdater::DNSimple(provider) => provider.delete(name, origin, record).await,
242            #[cfg(any(feature = "ring", feature = "aws-lc-rs"))]
243            DnsUpdater::Ovh(provider) => provider.delete(name, origin, record).await,
244            DnsUpdater::Porkbun(provider) => provider.delete(name, origin, record).await,
245            DnsUpdater::Rfc2136(provider) => provider.delete(name, origin, record).await,
246            DnsUpdater::Route53(provider) => provider.delete(name, origin, record).await,
247            DnsUpdater::Spaceship(provider) => provider.delete(name, origin, record).await,
248            DnsUpdater::GoogleCloudDns(provider) => provider.delete(name, origin, record).await,
249            #[cfg(feature = "test_provider")]
250            DnsUpdater::Pebble(provider) => provider.delete(name, origin, record).await,
251            #[cfg(feature = "test_provider")]
252            DnsUpdater::InMemory(provider) => provider.delete(name, origin, record).await,
253        }
254    }
255}