Kea DDNS

Warning

USE AT YOUR OWN RISK. This plugin interacts directly with the kea-dhcp-ddns daemon and modifies Kea configuration files. No OPNsense core files are modified — the plugin uses the standard plugins_configure() hook mechanism and survives OPNsense firmware updates without reinstallation.

Starting with OPNsense 26.1.5, the core includes built-in DDNS support. This plugin can be installed alongside core DDNS but only one should be active at a time. See Coexistence with core DDNS for details.

The Kea DDNS plugin adds Dynamic DNS (DDNS) support for the Kea DHCP server in OPNsense. It manages the kea-dhcp-ddns daemon and injects per-subnet DDNS parameters into both kea-dhcp4.conf and kea-dhcp6.conf using the OPNsense plugins_configure() hook mechanism. Since OPNsense 26.1.5, the core also includes DDNS support — the plugin can run side by side with it and offers additional features such as global DDNS defaults, shared TSIG keys, a status dashboard, and DHCPv6 Rapid Commit (see Coexistence with core DDNS).

When enabled, Kea automatically creates forward (A/AAAA) and reverse (PTR) DNS records as DHCP leases are assigned, and removes them when leases expire. Updates are sent as RFC 2136 DNS UPDATE requests, optionally authenticated with TSIG keys (RFC 2845).

Package:

os-kea-ddns

Navigation:

Services ‣ Kea Dynamic DNS ‣ Settings

Key features:

  • TSIG key management with auto-generation (HMAC-MD5 through HMAC-SHA512)

  • Forward and reverse DNS zone configuration with reverse zone auto-derive

  • Per-subnet DDNS policy for both DHCPv4 and DHCPv6

  • Automatic overlay injection into kea-dhcp4.conf and kea-dhcp6.conf

  • DHCID conflict resolution modes (RFC 4703)

  • DDNS status dashboard with daemon statistics and per-lease DDNS info

  • Log file viewer for kea-dhcp-ddns

Prerequisites

Before configuring this plugin, ensure:

  • OPNsense 26.1 or later. No core patches required — the plugin uses the standard kea_sync configure hook.

  • Kea DHCP is installed and enabled (DHCPv4 and/or DHCPv6) with at least one subnet configured.

  • A DNS server (e.g. BIND, PowerDNS, Knot) that accepts RFC 2136 dynamic updates for your forward and reverse zones.

  • A TSIG key shared between the DNS server and OPNsense. You can generate one using the built-in Generate button in the TSIG Keys tab, or on the DNS server with:

    tsig-keygen -a hmac-sha256 ddns-key.example.com
    
  • For IPv4 reverse DNS: an in-addr.arpa zone on the DNS server (e.g. 168.192.in-addr.arpa).

  • For IPv6 reverse DNS: an ip6.arpa zone on the DNS server (e.g. 6.5.4.3.2.1.d.f.ip6.arpa for fd12:3456::/32).

Settings

Navigate to Services ‣ Kea Dynamic DNS ‣ Settings.

The interface has six tabs: Settings, TSIG Keys, Forward Zones, Reverse Zones, Subnet DDNS, and Subnet6 DDNS.

Option

Description

Enabled

Enable the kea-dhcp-ddns daemon and activate DDNS overlays for Kea DHCPv4 and DHCPv6.

Manual config

Disable automatic generation of kea-dhcp-ddns.conf and manage the file manually at /usr/local/etc/kea/kea-dhcp-ddns.conf.

DDNS Defaults

These global defaults are emitted as Kea root-level parameters and inherited by all subnets. Per-subnet DDNS assignments default to “Use global default” — only explicitly set values override these globals.

Option

Description

Qualifying suffix

Default FQDN suffix appended to bare hostnames (e.g. dyn.example.com.). Must end with a dot. Can be overridden per subnet.

Send updates

Default for sending DDNS updates. Default: enabled. Can be overridden per subnet.

Update on renew

Default for sending DNS updates on lease renewals. Default: enabled. Can be overridden per subnet.

Replace client name

Default for replacing client-sent hostnames. Options: Never (default), Always, When present, When not present. Can be overridden per subnet.

Conflict resolution

Default DHCID conflict resolution mode. Options: Check with DHCID (default), No check, store DHCID, Check exists with DHCID, No check, no DHCID. Can be overridden per subnet.

Generated prefix

Default prefix for auto-generated hostnames when replacing client name (Kea default: myhost). Can be overridden per subnet.

Status

Navigate to Services ‣ Kea Dynamic DNS ‣ Status.

The status page provides real-time visibility into the kea-dhcp-ddns daemon and DDNS-registered leases. It has two tabs:

Shows the current state of the kea-dhcp-ddns daemon, queried via its Unix control socket (/var/run/kea/kea-ddns-ctrl-socket).

Daemon info:

  • Version — Kea DDNS daemon version

  • PID — process ID

  • Uptime — how long the daemon has been running

Update Statistics — global counters for DDNS operations:

Statistic

Description

NCR received

Name Change Requests received from DHCPv4/v6 daemons

NCR invalid

Malformed NCRs rejected

NCR error

NCRs that could not be processed

Queue full

NCRs dropped because the internal queue was full

Updates sent

DNS UPDATE requests sent to DNS servers

Updates successful

DNS updates that completed successfully

Updates error

DNS updates that failed (check the log for RCODEs)

Updates timeout

DNS updates that timed out (DNS server did not respond)

Updates signed

DNS updates authenticated with TSIG

Updates unsigned

DNS updates sent without TSIG authentication

Per-Key Statistics — if TSIG keys are in use, shows sent/success/error/timeout counters broken down by TSIG key name.

Click Refresh to reload the daemon status.

Note

If the daemon is not running, a warning is displayed. Start it by enabling DDNS in the Settings tab and clicking Apply.

Log File

The kea-dhcp-ddns daemon logs are available at Services ‣ Kea Dynamic DNS ‣ Log File.

Common log messages:

  • DHCP_DDNS_NO_MATCH: A client’s FQDN did not match any configured forward zone. Check your forward zone configuration and qualifying suffixes.

  • DHCP_DDNS_FORWARD_ADD_OK: Forward DNS record successfully added.

  • DHCP_DDNS_REVERSE_ADD_OK: Reverse DNS record successfully added.

  • DHCP_DDNS_FORWARD_REPLACE_REJECTED: DNS server rejected the update (check TSIG key, zone permissions, or DHCID conflicts).

Configuration examples

DHCPv4 DDNS with BIND

This example configures DDNS for a DHCPv4 subnet 192.168.1.0/24 with updates sent to a BIND DNS server at 192.168.1.53 for the forward zone dyn.example.com and reverse zone 1.168.192.in-addr.arpa.

On the DNS server, create the TSIG key and configure the zones to allow dynamic updates:

# Generate TSIG key
tsig-keygen -a hmac-sha256 ddns-key.dyn.example.com

# In named.conf, add the key and allow-update for both zones:
key "ddns-key.dyn.example.com" {
    algorithm hmac-sha256;
    secret "<base64-secret>";
};

zone "dyn.example.com" {
    type master;
    file "dyn.example.com.zone";
    allow-update { key ddns-key.dyn.example.com; };
};

zone "1.168.192.in-addr.arpa" {
    type master;
    file "1.168.192.in-addr.arpa.zone";
    allow-update { key ddns-key.dyn.example.com; };
};

On OPNsense, go to Services ‣ Kea Dynamic DNS ‣ Settings and configure:

Option

Value

Enabled

X

Qualifying suffix

dyn.example.com.

Send updates

X

Conflict resolution

Check with DHCID (RFC 4703)

Press Apply to activate. The kea-dhcp-ddns daemon starts and Kea DHCPv4 begins sending DDNS updates.

A client named laptop obtaining a lease at 192.168.1.100 will get:

  • Forward: laptop.lan.dyn.example.com192.168.1.100 (A record)

  • Reverse: 100.1.168.192.in-addr.arpalaptop.lan.dyn.example.com (PTR record)

DHCPv6 DDNS

This example adds DHCPv6 DDNS for a fd12:3456:789a:feed::/64 subnet, reusing the same DNS server, TSIG key, and forward zone from the DHCPv4 example above.

On the DNS server, add the IPv6 reverse zone:

zone "a.9.8.7.6.5.4.3.2.1.d.f.ip6.arpa" {
    type master;
    file "fd12-3456-789a.ip6.arpa.zone";
    allow-update { key ddns-key.dyn.example.com; };
};

On OPNsense, add a reverse zone and subnet6 DDNS assignment:

Add a new reverse zone:

Option

Value

Zone name

a.9.8.7.6.5.4.3.2.1.d.f.ip6.arpa

DNS server

192.168.1.53

Port

53

TSIG key

ddns-key.dyn.example.com

Press Save.

Press Apply. DHCPv6 clients on this subnet will now get AAAA and ip6.arpa PTR records.

Tip

For dual-stack environments where hosts have both DHCPv4 and DHCPv6 leases, use No check, store DHCID for the DHCPv6 conflict resolution. DHCPv4 and DHCPv6 generate different DHCID records for the same hostname, so the strict Check with DHCID mode will cause v6 updates to fail if v4 already created a DHCID for that name.

Multiple forward zones

If clients on different subnets use different DNS zones, create multiple forward zones and set the appropriate qualifying suffix on each subnet DDNS assignment.

For example, with subnets for LAN (lan.dyn.example.com) and corporate (corp.dyn.example.com), both under the parent zone dyn.example.com:

  • Create one forward zone: dyn.example.com (the parent zone handles both subdomains).

  • On the LAN subnet, set qualifying suffix to lan.dyn.example.com.

  • On the corporate subnet, set qualifying suffix to corp.dyn.example.com.

Both laptop.lan.dyn.example.com and printer.corp.dyn.example.com will match the dyn.example.com forward zone.

Troubleshooting

DDNS updates not appearing

  1. Check the kea-dhcp-ddns daemon log at Services ‣ Kea Dynamic DNS ‣ Log File.

  2. Look for DHCP_DDNS_NO_MATCH — this means the client’s FQDN doesn’t match any forward zone. Ensure the qualifying suffix produces an FQDN that is a subdomain of a configured forward zone.

  3. Verify the kea-dhcp-ddns daemon is running:

    keactrl status
    
  4. Check that dhcp_ddns=yes in /usr/local/etc/kea/keactrl.conf.

Forward updates fail, reverse never attempted

When a forward DNS update fails, Kea aborts the entire transaction including the reverse update. Check the kea-dhcp-ddns log for the RCODE:

  • RCODE 8 (NXRRSET): The DNS name already exists with a different DHCID or no DHCID at all. This happens when static DNS records exist without DHCID records. Change the conflict resolution to No check, store DHCID.

  • RCODE 9 (NOTAUTH): The DNS server is not authoritative for the zone, or TSIG authentication failed. Verify the zone name, TSIG key name, algorithm, and secret match exactly.

  • RCODE 5 (REFUSED): The DNS server refused the update. Check that allow-update is configured for the zone on the DNS server.

DHCPv6 clients send full FQDNs

Unlike DHCPv4 clients which typically send a bare hostname (e.g. laptop), DHCPv6 clients send their full FQDN via Option 39 (e.g. laptop.example.com.). This means:

  • The qualifying suffix is not appended when the client already sends a complete FQDN.

  • The FQDN the client sends must match a configured forward zone.

  • If clients send FQDNs in a different domain than your DDNS forward zone, you may need to add that domain as an additional forward zone.

Stale DNS records after hostname changes

When a DHCP reservation hostname is changed, existing leases retain the old hostname until the client renews. To force an immediate update:

  1. Delete the lease via the Kea control socket or the Leases page.

  2. Re-add the lease with the new hostname (or wait for the client to renew).

  3. Trigger a DDNS resend.

The old DNS records (A/AAAA, PTR, DHCID) are not automatically cleaned up. Remove them manually using nsupdate or your DNS server’s management interface.

How it works

The plugin integrates with the core Kea DHCP service using the standard plugins_configure() mechanism. When Kea is started, restarted, or reconfigured, the kea_sync event fires. OPNsense processes all registered plugins alphabetically:

  1. Core (kea.inc) runs kea_configure_do() — generates kea-dhcp4.conf and kea-dhcp6.conf as JSON files.

  2. This plugin (kea_ddns.inc) runs kea_ddns_configure_do() — reads those JSON files, merges DDNS parameters (global settings and per-subnet overlays), writes them back, generates kea-dhcp-ddns.conf, and enables the DDNS daemon in keactrl.conf.

This approach requires no modifications to OPNsense core files. The plugin survives OPNsense firmware updates without reinstallation.

The kea-dhcp-ddns daemon listens on 127.0.0.1:53001 and receives Name Change Requests (NCRs) from the DHCPv4 and DHCPv6 daemons over a local connection. It then translates these into RFC 2136 DNS UPDATE requests sent to the configured DNS servers.

Coexistence with core DDNS

Starting with OPNsense 26.1.5, the core includes built-in DDNS support for Kea (see core PR #9923). The plugin can be installed alongside core DDNS — use one or the other, not both at the same time.

Both the core and the plugin register on the kea_sync hook. Alphabetical ordering (kea.inc < kea_ddns.inc) means the plugin always runs second, post-processing the core’s generated configuration. If both are enabled simultaneously, the plugin takes precedence.

Recommended usage:

  • Plugin only — keep core DDNS disabled (the default at Services ‣ KEA DHCP ‣ Settings). The plugin handles everything independently.

  • Core only — disable the plugin in Services ‣ Kea Dynamic DNS ‣ Settings. A disabled plugin is fully inert and does not interfere with core DDNS.

  • Switching — you can switch between the two at any time. Disable one before enabling the other, then click Apply.

The plugin offers additional features not available in the core implementation:

  • Global DDNS defaults (qualifying suffix, send updates, conflict resolution, etc.) that all subnets inherit, with per-subnet overrides where needed

  • Shared TSIG keys across multiple subnets and zones (core requires a separate TSIG key per subnet)

  • Reverse zone auto-derive from Kea subnets

  • DDNS status dashboard with daemon statistics and per-lease DDNS info

  • Log file viewer for the kea-dhcp-ddns daemon

  • DHCPv6 DDNS support with Rapid Commit

Note

These interaction scenarios have been tested on OPNsense 26.7.a_328 using the automated interaction test suite (scripts/ddns_interaction_test.sh). The test covers five scenarios: core-only, plugin-only, both enabled, plugin disabled with core active, and cleanup after plugin removal. All 56 tests pass.

Uninstall

Remove the package:

pkg delete os-kea-ddns

This removes all plugin files, disables DDNS in keactrl.conf, and removes kea-dhcp-ddns.conf. No core files are modified or need to be restored.

API

All configuration is available via the REST API under /api/keaddns/general/.

Endpoint

Method

Description

/api/keaddns/general/get

GET

Get general settings (enabled, manual_config)

/api/keaddns/general/set

POST

Save general settings