zone-update 0.10.1

A library of CRUD-like operations on DNS zones for multiple providers
Documentation

Zone Update

Crates.io Docs.rs GitHub CI License

A minimal Rust library providing CRUD-like operations on DNS records with various DNS providers.

Overview

Zone Update is a lightweight library that provides a simple interface for programmatically managing DNS zone records through provider APIs. The library is both blocking and async, and supports multiple async runtimes (see below).

Supported DNS providers

Currently, Zone Update supports the following DNS providers:

  • Cloudflare
  • deSEC
  • DigitalOcean
  • Dnsimple
  • DnsMadeEasy
  • Gandi
  • Linode
  • Porkbun

See the DNS providers matrix for more details.

Supported platforms

zone-update supports both blocking and async APIs. For async the library attempts to be as provider-agnostic; it is known (tested) to work with the following runtimes:

zone-update is tested against Linux, Mac & Windows.

Feature flags

Each DNS provider is gated behind their name, however all provider are enabled by default. To limit the providers you can add zone-update to your Cargo.toml in the following format:

zone-update = { version = "*", default-features = false, features = ["digitalocean", "desec"] }

The other notable flag is async, which is not enabled by default.

Usage

Basic Example

use zone_update::{gandi, DnsProvider, errors::Result};
use std::net::Ipv4Addr;

fn update_gandi_record() -> Result<()> {
    let config = zone_update::Config {
        domain: "example.com".to_string(),
        dry_run: false,
    };
    
    let auth = gandi::Auth::ApiKey("your-api-key".to_string());
    let client = gandi::Gandi::new(config, auth);
    
    let host = "www";
    let new_ip = Ipv4Addr::new(192, 0, 2, 1);

    // Update the A record for www.example.com
    client.update_a_record(host, &new_ip)?;
    
    Ok(())
}

Provider lookup from configuration file

The Provider enum supports deserialisation with serde, which allows runtime lookup of DNS providers from a configuration file:

use serde::Deserialize;
use zone_update::{Provider, errors::Result};
use std::net::Ipv4Addr;

const CONFIG_TOML: &str = r#"
domain = "example.com"
dry_run = true

[provider]
name = "porkbun"
key = "my_key"
secret = "my_secret"
"#;

#[derive(Deserialize)]
pub struct MyConfig {
    domain: String,
    dry_run: bool,
    provider: Provider,
}

fn update_website_record() -> Result<()> {
    let config: MyConfig = toml::from_str(CONFIG_TOML).unwrap();

    let zu_config = zone_update::Config {
        domain: config.domain,
        dry_run: config.dry_run,
    };

    let client = config.provider
        .blocking_impl(zu_config);

    let host = "www";
    let new_ip = Ipv4Addr::new(192, 0, 2, 1);

    // Update the A record for www.example.com
    client.update_a_record(host, &new_ip)?;

    Ok(())
}

See the examples directory for other use-cases.

Contributing

At this point the most useful contributions would be to add additional DNS provider APIs. However other contributions are welcome.

Steps for adding a new provider

This needs to be expanded, and the existing implementations are currently your best reference, but is a basic checklist:

  • Create a new module directory under src and add mod.rs and (recommended) types.rs. Create the appropriate features flags in Cargo.toml.
  • Add the necessary type structures with serde annotations; you will need to consult the API documentation and/or experiment with curl.
  • Create a structure for the provider implementation (usually just wrapping Auth & Config.
  • Implement the core CRUD operations in the DnsProvider trait for this struct. This tends to be provider-specific, but most follow on of several patterns. The existing implementations can be consulted as a reference.
  • Use the generate_helpers macro to fill out the rest of the trait.
  • Create a test module and use the generate_tests macro to create the standard tests.
  • Run the tests against a sandbox or working account (Do Not Skip This Step).
  • Once the blocking API implemented the async implementation is generated by macros. See an existing provider impl.
  • Add you provider to the Provider enum and its impl.
  • Raise a PR.

AI Contribution Policy

This reason this project will not accept runtime code generated by AI. Generation of draft documentation and test code is acceptable, but should be reviewed by the submitter before raising a PR.

License

This project is licensed under either of:

at your option.