Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - brendanbank

#1
Hi all,

I've been working on adding Dynamic DNS (DDNS) support to the Kea DHCP plugin in OPNsense and would love to get feedback before submitting a pull request.

Why this feature?

I'm in the process of migrating from ISC DHCP to Kea DHCP, but one of the blockers for me (and I suspect others) is the lack of DDNS support — the ability to automatically register forward (A) and reverse (PTR) DNS records when leases are handed out. This was available in ISC DHCP via nsupdate and is something I rely on in my network. With ISC DHCP reaching end-of-life, having feature parity in Kea is important for a smooth migration.

What it does

  • Integrates the Kea DHCP-DDNS daemon (D2) with the existing Kea DHCPv4 plugin
  • TSIG key management (HMAC-SHA256, HMAC-SHA512, etc.) for authenticated DNS updates (RFC 2845)
  • DDNS domain profiles with configurable forward and reverse zones, DNS server addresses, and per-zone TSIG keys
  • Per-subnet DDNS configuration with automatic hostname prefix options:
      Network name — uses the OPNsense interface description (e.g. mylan.dyn.example.com)
      Interface name — uses the physical interface name (e.g. vlan0.021.dyn.example.com)
      Custom prefix — free-form input
      No prefix — hostnames placed directly under the zone
  • Reverse zone auto-computation from subnet CIDR, with manual override for non-standard delegations (e.g. 10.in-addr.arpa instead of per-/24 zones)
  • DHCID conflict resolution (RFC 4703) enabled by default

Future plans

IPv6 (DHCPv6) DDNS support with AAAA and ip6.arpa PTR records is planned as a follow-up.

Code and documentation


A note on the implementation: I'm proficient in Python but not so much in PHP, so I've used Claude Code to help write the PHP code. The implementation follows the existing OPNsense MVC patterns and has been tested on a production firewall with BIND9 as the DNS server, with both forward and reverse updates working correctly across multiple subnets with TSIG authentication. That said, an extra pair of eyes on the PHP would be very welcome.

I'd appreciate any feedback on the approach, the UI/UX, or the code itself before I open a PR against the main repos.

Thanks,
Brendan
#2
Sorry I then I did not explain myself properly.

I have a bunch of secondary configured in the BIND Plugin. If I make a change through the web interface, the named.conf file at /usr/local/etc/namedb/named.conf will be regenerated from the /usr/local/opnsense/service/templates/OPNsense/Bind/named.conf template.

/usr/local/bin/named does not allow updates on the secondary zone as they should be done to the primary zone. Hence named throws an error:
/usr/local/etc/namedb/named.conf:93: option 'update-policy' is not allowed in 'secondary' zone 'xx.xx.xx.in-addr.arpa'

In the secondary zone configuration block, 'update-policy' seems not to be allowed - this is a snippet from the generated name.conf file:

zone "xx.xx.xx.in-addr.arpa" {
        type secondary;
        primaries { yy.yy.yy.yy key "key.dyn.zz.zz.zz"; };
        file "/usr/local/etc/namedb/secondary/xx.xx.xx.in-addr.arpa.db";
        allow-transfer {
                ns_notify;
        };
        allow-query {
                ns_query;
        };
        update-policy {
                grant rndc-key zonesub ANY;
        };
};


Here is the patch that fixes it:

Y@Z:/usr/local/opnsense/service/templates/OPNsense/Bind % diff named.conf.org named.conf
183c183
< {%      if domain.allowrndcupdate is defined and domain.allowrndcupdate == "1" %}
---
> {%      if domain.allowrndcupdate is defined and domain.allowrndcupdate == "1" and domain.type != 'secondary' %}


I'll create an issue for this bug.

https://github.com/opnsense/plugins/issues/3874

Thanks,

- Brendan
#3
I've updated to OPNsense 24.1.4-amd64 yesterday.

My firewalls run a secondary zone to ensure that when they lose connectivity, names are still resolving.

When I update the zone file through the GUI named stops working with the following error:
[root@casa /var/log/system]# service named start
/usr/local/etc/namedb/named.conf:61: option 'update-policy' is not allowed in 'secondary' zone 'xxxxxx.xxx'


Any solution for this?

Thanks,

- Brendan
#4
I just had another crash. I'm considering downgrading at the end of our workday. As a workaround, I've disabled unbound and enabled Dnsmasq to do the DNS resolving.
#5
Interfaces setting was set to 'All' but that setting does not seem to be available anymore and I've enabled all interfaces manually. 
#6
Same here, I've upgraded to 20.7.7 to get IPv6 prefix delegation working again, however, unbound crashed twice since I've upgraded:

root@fw:~ # dmesg | grep unbound
pid 85049 (unbound), jid 0, uid 59: exited on signal 11


Here is my unbound config:

  <unbound>
    <enable>1</enable>
    <custom_options/>
    <regdhcp>1</regdhcp>
    <cache_max_ttl/>
    <cache_min_ttl/>
    <incoming_num_tcp>10</incoming_num_tcp>
    <infra_cache_numhosts>10000</infra_cache_numhosts>
    <infra_host_ttl>900</infra_host_ttl>
    <jostle_timeout>200</jostle_timeout>
    <log_verbosity>1</log_verbosity>
    <msgcachesize>4</msgcachesize>
    <num_queries_per_thread>4096</num_queries_per_thread>
    <outgoing_num_tcp>10</outgoing_num_tcp>
    <unwanted_reply_threshold/>
    <hosts>
      <host>******</host>
      <domain>*********</domain>
      <rr>A</rr>
      <ip>***********</ip>
      <mxprio/>
      <mx/>
      <descr/>
      <aliases>
        <item/>
      </aliases>
    </hosts>
    <hosts>
      <host>******</host>
      <domain>*********</domain>
      <rr>A</rr>
      <ip>**********</ip>
      <mxprio/>
      <mx/>
      <descr/>
      <aliases>
        <item/>
      </aliases>
    </hosts>
    <hosts>
      <host>******</host>
      <domain>**********</domain>
      <rr>A</rr>
      <ip>**********</ip>
      <mxprio/>
      <mx/>
      <descr/>
      <aliases>
        <item/>
      </aliases>
    </hosts>
    <hosts>
      <host>******</host>
      <domain>*********</domain>
      <rr>A</rr>
      <ip>**********</ip>
      <mxprio/>
      <mx/>
      <descr/>
      <aliases>
        <item/>
      </aliases>
    </hosts>
    <regdhcpstatic>1</regdhcpstatic>
  </unbound>