Skip to content

Conversation

@chall37
Copy link

@chall37 chall37 commented Dec 8, 2025

Summary

This plugin automatically registers dnsmasq DHCP leases and static host entries in Unbound DNS, enabling local hostname resolution for DHCP clients.

Note: This plugin is intended as a stopgap solution until native integration between Unbound and a supported DHCP service is implemented in OPNsense core.

Related Issues

Features

  • Watches dnsmasq lease file and static hosts for changes
  • Registers A and PTR records in Unbound DNS
  • Supports multiple domains via dnsmasq IP-range-to-domain mapping
  • Deduplicates records (static entries take precedence over leases)
  • Automatic cleanup of stale records
  • System status notifications in OPNsense web UI
  • Periodic reconciliation to handle Unbound restarts

Requirements

  • OPNsense with Unbound DNS resolver enabled (remote control enabled by default)
  • dnsmasq plugin installed and configured with DHCP

Testing

Tested on OPNsense 24.7 with:

  • DHCP lease registration
  • Static host registration
  • Domain filtering
  • System status notifications
  • Service start/stop/restart

Registers dnsmasq DHCP leases and static hosts in Unbound DNS.
Features:
- TXT marker records for tracking managed entries
- Batch operations for efficiency
- Periodic reconciliation to handle orphaned records
- kqueue-based file watching on FreeBSD
- Update form field IDs from unbounddnsmasq to dnsmasqtounbound
  to match the renamed model
- Change enabled default from 0 to 1 so plugin is enabled by
  default on fresh install
- Fix file permissions (644 for Makefile/pkg-descr, 755 for scripts)
- Add .gitignore for work/ and __pycache__/
- Add plugins.inc.d integration for service widget, HA sync, syslog
- Add PHPDoc class comments to all PHP classes
- Update copyright year to 2025
DNS is case-insensitive, so OPNsense.lan and opnsense.lan should
be treated as the same hostname for deduplication purposes.
- Parse domain= lines from dnsmasq.conf for global and range-specific domains
- Use IP-based domain lookup instead of hardcoded 'lan' fallback
- Watch dnsmasq.conf for changes and trigger reconciliation
- Add system status notifications via OPNsense SystemStatus API
- Write status to /var/run/dnsmasq_watcher_status.json
- Add PHP status class to display notifications in web UI
- Log skipped records when IP not in any configured domain range
- Status levels: OK, WARNING (skipped records), ERROR (config/service issues)
- Update copyright year to 2025 in rc.d script
- Add README.md with installation and usage documentation
Unbound remote control is always enabled by default in OPNsense,
there is no UI setting to enable it. Updated README to reflect this.
@chall37 chall37 marked this pull request as ready for review December 8, 2025 21:08
@Monviech
Copy link
Member

Monviech commented Dec 8, 2025

https://docs.opnsense.org/manual/dnsmasq.html#dhcpv4-with-dns-registration

You wrote so much code for something that is already working natively for lots of people, was battle tested, and is the recommended default solution (even by the system wizard in 25.7).

Just saying this PR is DOA.

Document the shortcomings of each OPNsense DHCP option for Unbound
DNS integration:
- ISC DHCP: deprecated, watcher daemon crashes on bad hostnames
- Kea DHCP: no dynamic lease registration, static requires restart
- dnsmasq: built-in DNS only, forwarding has domain issues

References: opnsense/core#7475, #8075, #8612, #9277
Detail why Unbound-to-dnsmasq query forwarding is problematic:
- Brittle config sync or performance penalty (no fallback behavior)
- Requires private-domain and domain-insecure exemptions
- Known bugs with static reservations and domain overrides
@chall37
Copy link
Author

chall37 commented Dec 8, 2025

https://docs.opnsense.org/manual/dnsmasq.html#dhcpv4-with-dns-registration

You wrote so much code for something that is already working natively for lots of people, was battle tested, and is the recommended default solution (even by the system wizard in 25.7).

Just saying this PR is DOA.

https://github.com/chall37/plugins/tree/dnsmasq-to-unbound/dns/dnsmasq-to-unbound#background

There are various issues with dnsmasq integration with unbound, and the fact that it "works natively for lots of people" who don't mind the tradeoffs is why I created this as a plugin (among other reasons).

Making a PR to opnsense-core doesn't make sense for me, because the LOE of exploring the code and balancing the technological requirements with stakeholder expectations is also more than I can take on (though if I did, it would be focused on Kea integration, not dnsmasq). I needed a solution that works now, for myself, rather than trying to impose my personal philosophy and expectations on the core project. A plugin allows me (and potentially others) to maintain a working fix independent of unrelated updates to opnsense-core, provides streamlined deployment, and it lets me leverage the opnsense web ui to view dnsmasq-unbound mappings in realtime, surface status issues through the system status widget, and so forth.

Basically, this is a low-stakes way for me to contribute a working solution, to share a script I wrote to do this, packaged as a plugin. It solved a problem for me, it let me get my feet wet with writing opnsense plugins (just something to do with a little spare time I had), and it's simple enough that I don't mind being the maintainer for the foreseeable future, until it is rendered obsolete by improvements in the core project. If it helps out other folks, great -- if not, that's okay too.

@Monviech
Copy link
Member

Monviech commented Dec 9, 2025

The whole DNS infrstructure is based around forwarding and recursively querying authoritative name servers.

By saying that one more hop introduces insufferable latency undermines the whole DNS concept that exists for decades.

Are you sure there is no configuration issue that could be fixed in a forwarding setup that we might have missed to document?

@chall37
Copy link
Author

chall37 commented Dec 9, 2025 via email

@AdSchellevis
Copy link
Member

dnsmasq primary purpose is a bit in it's name.... but that's besides the point here ;)

It's obviously not a problem to build your own setup in any way you like, I just don't think it's a good idea to expose it in our plugin system.

We have had the "tail isc's leases and dump them into unboud" for years, which was always one of the most problematic components in our stack, mainly due to the fact that you can not warrant synchronicity properly, which means you will be hunted with edge-cases for the rest of your life.

Plugins for single use-cases are fine to exist (one of the reasons why we are so open with our development documentation), just shouldn't be shipped by us to all other users to avoid confusion and future maintenance issues/disappointments.

@chall37
Copy link
Author

chall37 commented Dec 9, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants