First of all thanks a lot for taking this feature (https://docs.opnsense.org/manual/dnsmasq.html#firewall-alias-ipset) directly into OPNsense user interface!
The general limitation I am seeing with current design in
Services > Dnsmasq DNS & DHCP > Domains
is, that IPSet/"Firewall alias" is artificially bound to forwarded DNS servers/"IP address". In Dnsmasq IPsets are just tied to domain names.
Here is an example:
screenshot.png
creates following config in /usr/local/etc/dnsmasq.conf:
server=/*/127.0.0.1#5335
rebind-domain-ok=/*/
server=/example.org/127.0.0.1#5335
ipset=/example.org/dns_resolved_ips
rebind-domain-ok=/example.org/
server=/example.org/1.1.1.1
ipset=/example.org/dns_resolved_ips
rebind-domain-ok=/example.org/
server=/example.org/1.1.1.1
ipset=/example.org/my_orga_unit
rebind-domain-ok=/example.org/
- This design suggerates, that a firewall alias is only filled, if DNS server of same entry has been chosen for forwarding.
But this is not the case. E.g. if example.org is resolved via 127.0.0.1:5335, then returned IP is stored both in `dns_resolved_ips` and `my_orga_unit` (despite latter alias defined for entry with 1.1.1.1). - Work is repetitive, if IPs are to be stored in multiple IPsets, as you need to specify `IP address` and `Port` in each entry. But server and port don't matter for IPsets at all.
- There also are duplicate entries in dnsmasq config created:
# no copy-and-paste mistake by me, this gets auto-generated
server=/example.org/1.1.1.1
server=/example.org/1.1.1.1
ipset=/example.org/dns_resolved_ips
ipset=/example.org/my_orga_unit
(Does that actually send DNS requests *twice* due to double entries, as dnsmasq will do concurrent queries to all servers, if "Query DNS servers sequentially" is not checked?)
- Pure dnsmasq config (https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html) would have entries like this:
server=/example.org/1.1.1.1
ipset=/example.org/dns_resolved_ips,my_orga_unit
- If you are used to dnsmasq notation `ipset=`, don't pay attention to hints and think "I just want to create an IPset for domain X, so leaving 'IP address' field for server empty", then domain won't be resolved at all, which seems a bit un-intuitive.
- An important case for me is to have one catch-all IPset, which captures *all* resolved IPs. dnsmasq allows this via # wildcard like `/#/dns_resolved_ips`. In OPNsense user interface, we currently can't do that. Setting `*` in `Domain` and selecting a "Firewall alias" results in error
QuoteTop level wildcard entries are not allowed for Ipset.
- Note that `ipset=` and `server=` in dnsmasq have kinda their own notation, so with current design, handling these specifics in one form is difficult, as you would end up mixing both notations.
- Another thing I noticed: Setting domain `*` as suggested here (https://docs.opnsense.org/manual/dnsmasq.html#dnsmasq-as-primary-dns-resolver) leads to `rebind-domain-ok=/*/` entry be automatically created in config file. Wouldn't this disable DNS rebinding checks for all domains?
SuggestionWhat about ditching "Firewall alias" in "Domains" and creating an additional tab "IPSet", which takes a domain (optional autocomplete from values in "Domains" tab) and a firewall alias name? This change would solve above issues and comes closer to the config model Dnsmasq has.
If you managed to read till here: Let know what you think!
The way it works right now is intentional, since it guides the user implicitly that domains that are entered must be resolvable by dnsmasq. This is because most users also run unbound.
Allowing a wildcard (#) to flush all resolved domains into an alias seems like its unecessary. The use case is clearly stated in the documentation, for allowlists regarding things like *.example.com or the like. It is just an extension of the other Alias types that exist for hostnames, not a solution for full alias management.
Work can be repetitive in most GUIs, a larger set can be imported via the API for example.
If you want full control, you can import a custom dnsmasq configuration file.
Quote from: Monviech (Cedrik) on October 04, 2025, 02:19:11 PMThe way it works right now is intentional, since it guides the user implicitly that domains that are entered must be resolvable by dnsmasq. This is because most users also run unbound.
Yes, I am using Unbound as upstream.
Not quite sure about your point. If using IPset feature, then Unbound as upstream recursive resolver seems to be the preferred solution by docs - otherwise an additional external resolver would be needed to prevent loops.
In this case all queries are forwarded via wildcard / `*`. If a domain is resolvable will be determined by upstream. IPSet feature picks up those domains from the wildcard forwarding, that are interesting to be stored for firewall rules.
Or did you primarily have the case Unbound -> Dnmasq in mind?
QuoteAllowing a wildcard (#) to flush all resolved domains into an alias seems like its unecessary. The use case is clearly stated in the documentation, for allowlists regarding things like *.example.com or the like. It is just an extension of the other Alias types that exist for hostnames, not a solution for full alias management.
That wildcard is indeed intended for allowlists:
Allow everything, that explicitly has been resolved by primary DNS resolver of OPNsense. This enables whitelisting solely by domains, not static IPs.
QuoteIf you want full control, you can import a custom dnsmasq configuration file.
Yeah, that's what I am doing now. But I hoped to finally get all settings smoothly integrated in OPNsense GUI for better maintainability, now Dnsmasq is the standard DNS/DHCP server.
Getting all settings included in all combinations is very hard.
The man page has quite some directives, some features will be limited in some way.
The scope in which the features work right now is pretty clear. A new grid just for ipset will not be created.
What could be a possibility though is to improve the validation so that a domain must not necessarily have an IP address or port defined. Such a scope would be managable to solve.
The issue sounds mostly input validation related.
Create a clear scoped ticket here and we can probably solve that:
https://github.com/opnsense/core
Done:
https://github.com/opnsense/core/issues/9262
https://github.com/opnsense/core/issues/9263
https://github.com/opnsense/core/issues/9264
Thanks for your work.