Skip to content

stintel/ddns-mux

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ddns-mux

A DNS UPDATE multiplexer that fans out TSIG-signed RFC 2136 dynamic DNS updates from a single sender (kea-dhcp-ddns) to multiple PowerDNS targets, re-signing each outbound update with the target's own TSIG key.

Written in Rust with hickory-proto, tokio, and serde/toml.

Why

You have kea-dhcp-ddns handing out DHCP leases and updating DNS records via RFC 2136, but your DNS infrastructure spans multiple PowerDNS nodes (e.g. different zones, different data centers, or just redundancy). Kea can send updates to only one target. You need them delivered to all of them, each with its own TSIG signature.

The native PowerDNS answer would be a database backend with active-active replication — but that means maintaining yet another MySQL/MariaDB cluster. This project is an alternative: a small, safe, zero-database middlebox.

Architecture

kea-dhcp-ddns ──(TSIG-signed UPDATE)──► ddns-mux
                                           │
                                           ├─(per-target TSIG)──► pdns-1
                                           ├─(per-target TSIG)──► pdns-2
                                           └─(per-target TSIG)──► pdns-3
  1. ddns-mux listens for DNS UPDATE messages over both UDP and TCP.
  2. Each inbound message is verified against the configured TSIG key.
  3. The update is fanned out concurrently to all configured targets.
  4. Each target receives its own TSIG-signed copy of the update.
  5. A confirmation strategy determines the aggregate result returned to kea:
    • all (default): every target must succeed
    • any: at least one target must succeed
  6. A TSIG-signed response is sent back to the original sender.

Forwarding uses UDP first, falling back to TCP if the response is truncated. A 5-second timeout applies to each target.

Configuration

See config.toml.example:

listen_tcp = "127.0.0.1:5353"
listen_udp = "127.0.0.1:5353"
require_confirmation = "all"

[incoming_tsig]
algorithm = "hmac-sha256"
key = "base64-encoded-secret=="
name = "kea-ddns-key."

[[targets]]
address = "192.168.1.1:53"
[targets.tsig]
algorithm = "hmac-sha256"
key = "base64-encoded-secret-for-pdns1=="
name = "ddns-mux-pdns1."

[[targets]]
address = "192.168.1.2:53"
[targets.tsig]
algorithm = "hmac-sha256"
key = "base64-encoded-secret-for-pdns2=="
name = "ddns-mux-pdns2."

Supported algorithms: hmac-sha256, hmac-sha384, hmac-sha512.

Building & Running

cargo build --release
./target/release/ddns-mux /path/to/config.toml

Logging is handled by tracing. Set the level via RUST_LOG (e.g. RUST_LOG=info).

Credits

This project was built with the assistance of AI coding agents:

  • Claude Code (Anthropic)
  • Codex (OpenAI)
  • Gemini CLI (Google)
  • OpenCode with Qwen 3.6 27B

Issues & Pull Requests

This GitHub repository is a read-only mirror of my internal workspace. Issues and Pull Requests are currently disabled. If you have feedback or patches, feel free to reach out to me directly. If the project becomes popular, I will reconsider this.

About

TSIG-signed RFC 2136 DNS UPDATE multiplexer and proxy for multi-target fanout.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

 

Packages

 
 
 

Contributors

Languages