Per DHCP server domain suffixes

hi,

i have several interfaces (bridges) on different subnets, each having an independent DHCP server. i need different domain suffixes appended to hostnames on the different subnets.

LuCI does not seem to support this. so in /etc/config/dhcp, i tried adding this:

config dhcp 'lan'
	...
	option domain 'my.lan'

then this:

config dhcp 'lan'
	...
	list dhcp_option '15,my.lan'

but neither worked. how can i do this?

thank you!

also, i noticed that bare hostnames without domain qualification resolve, which is also a problem. i need somehost.my.lan to resolve, but not bare somehost.

thanks again

EDIT:

i suppose this second part could be fixed by eliminating this setting?

config dnsmasq
	...
	option local '/lan/'

but what about the main issue?

If you want different search domains per interface, assign DHCP Option 119 - see:

thank you.

i do this with a single instance of dnsmasq in DDWRT with no issues. dnsmasq can handle several independently configured DHCP servers within an instance with no issues. also, i think running several instances means that subnets will not be able to resolve hosts of other subnets, which is not acceptable.

there must be a way to do this with a single dnsmasq instance.

thanks but no, i dont care about searches at this point, i care about the suffixes that get appended to hostnames.

That's not correct.

1 Like

how do one dnsmasq instance know of the hosts of the others if each instance has a separate lease file?

from the linked post:

uci set dhcp.${INST}_dns.leasefile="/tmp/dhcp.leases.${INST}"

thanks

hi,

according to https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html --domain together with --dhcp-fqdn options can do what you want (or what i understand you may want).
both option is supported by uci config style in the main section.

Then that's DHCP Option No. 15.

config dhcp 'lan'
        option instance 'lan_dns'
        option interface 'lan'
        option start '100'
        option limit '150'
        option leasetime '12h'
        option dhcpv4 'server'
        list dhcp_option '15,example.com'

You assign desired domain to each interface via DHCP config.

1 Like

Apart from what @vgaetera mentioned, you can use the list server '/tld/IP_ADDRESS' where the other instance is listening.

1 Like

thanks. as you can see in my first post, this is the first thing i tried and it didn't work.

hi,

thanks. you are right, --dhcp-fqdn is needed to allow name clashes between subnets. (leaving this out allows the guest network to do a DoS attack on a trusted network.)

it's --domain i'm having trouble with, i'm reaserching now.

also per-dhcp --local defs are needed (in the general case) to close the local domain and forbid outgoing requests to the internet for non-existent hosts. however in my use, local domains are of the form subdomain.lan, so a single --local for lan MIGHT suffice.

also --domain-needed, but its already there.

note that no solution based on dhcp_option can ever work, as dhcp_option only adds fields sent to clients, while the problem is that dnsmasq is misconfigured and thinks i want a single namespace for all DHCP servers.

once dnsmasq is correctly configured, it should already send the right domain suffix to clients and not need dhcp_option, i believe.

also, all solution talking about multiple dnsmasq instances are not solutions for me: dnsmasq is totally able to handle what i want with a single instance, so multiple instances are hacks to sidestep the current misconfiguration and i don't want them.

FYI:

i filed a bug related to this: https://github.com/openwrt/openwrt/issues/13732

(however, as stated before, dhcp_option is not the solution for me.)

Apologies, I originally [mis]understood you wanted one instance of dnsmasq to append different domains to the hostname of clients - depending on thier connected interface.

Cool.

that's what i want, but dhcp_option does not do that at all! dhcp_option sends a specific domain to clients over DHCP. but dnsmasq does not try to parse these options. dnsmasq, no matter the override of its response, still think the hosts are in one domain an sets the same suffix for all in its database. dhcp_option only causes a disconnection between what dnsmasq thinks and what clients think.

2 Likes

Solution

yes, you can serve different domain suffixes on different DHCP servers using a single instance of dnsmasq. you simply need these options added to dnsmasq.conf:

domain-needed
dhcp-fqdn
local=\lan\
domain=main.lan
domain=main.lan,br-lan
domain=guest.lan,br-guest
domain=iot.lan,br-iot

unfortunately there is no way of doing this without hacking the code of openwrt. not only is UCI for dnsmasq incomplete, it also does not allow passing arbitrary extra options to it... enormous #facepalm.

i want to discuss fixing all these issues with the maintainer, but i don't know who he is.

Steps

  1. you might want to install openwrt's SFTP server to make file editing easier from you host.

  2. in LUCI, in DHCP and DNS, check "Domain required", set "Local server" to \lan\, and "Local domain" to main.lan.

  3. in shell, set --dhcp-fqdn:

uci set dhcp.@dnsmasq[0].fqdn='1'
uci commit dhcp
  1. create file /etc/extra-dnsmasq.conf:
# extra config from /etc/extra-dnsmasq.conf

domain=main.lan,br-lan
domain=guest.lan,br-guest
domain=iot.lan,br-iot
  1. create a service /etc/init.d/extra-dnsmasq-conf that will hack dnsmasq code before it runs, and mark it as executable:
#!/bin/sh /etc/rc.common

# enable with: /etc/init.d/extra-dnsmasq-conf enable

START=18

start() {
	sed -i 's|mv -f $CONFIGFILE_TMP $CONFIGFILE|cat /etc/extra-dnsmasq.conf >> $CONFIGFILE_TMP; mv  -f $CONFIGFILE_TMP $CONFIGFILE|' /etc/init.d/dnsmasq
}
  1. add these lines to /etc/sysupgrade.conf, to make the previous files persistent across sysupgrades:
/etc/init.d/extra-dnsmasq-conf
/etc/rc.d/S18extra-dnsmasq-conf
/etc/extra-dnsmasq.conf
  1. in shell, enable the new service:
/etc/init.d/extra-dnsmasq-conf enable

now reboot and everything should work.

Note

you might want to forbid guest clients to query hosts on your private networks. for this, you just avoid adding a forwarding traffic rule in the firewall from the isolated guest network to your private DNS server (but one for your DHCP server is obviously needed). but with only this change, clients on the guest network will be unable to resolve any DNS queries because the DNS they get advertised from DHCP is unreachable.

the solution is adding a DHCP-Option in advanced settings of the DHCP server of the guest interface that overrides the IP of the local DNS server normally advertised with a public one. one possible value for the option is 6,1.0.0.1,1.1.1.1, which directs guest DNS queries to the public clouldflare servers.

Note 2

openwrt has a way of including dnsmasq config text, so the hacking i did before is unnecessary.

  • /etc/dnsmasq.cfgXXXX.conf: applies to instance /var/etc/dnsmasq.conf.cfgXXXX.
  • /etc/dnsmasq.conf: applies to instances without a /etc/dnsmasq.cfgXXXX.conf file.

from the dnsmasq init.d script:

	local dnsmasqconffile="/etc/dnsmasq.${cfg}.conf"
	if [ ! -r "$dnsmasqconffile" ]; then
		dnsmasqconffile=/etc/dnsmasq.conf
	fi

	# if we did this last, we could override auto-generated config
	[ -f "${dnsmasqconffile}" ] && {
		xappend "--conf-file=${dnsmasqconffile}"
	}

i did not notice before because files are not included, they are referenced in the command line instead.

more than that is needed IMHO.

in dhcp section:

  • add domain (string):
    • if not null: adds domain=<domain>,<if-name>
    • default null
  • add domain_local (boolean):
    • if true and domain not null: adds local=\<domain>\
    • default true

in dnsmasq section:

  • add fqdn (boolean) support in LUCI (UCI already exists)
    • default is false already
  • add domain_local (boolean):
    • if true and domain not null: adds local=\<domain>\
    • default true
    • this addition requires migration
  • remove local:
    • this setting allows multiple values and a way to set those already exists (DNS forwardings).
    • this removal requires migration

migration for dnsmasq section:

  • if local not null:
    • if local == domain:
      • set domain_local true
    • else:
      • set domain_local false
      • add value of local verbatim as an entry in the "DNS forwardings" list
        (local and server options are aliases)
    • remove local to finish migration

alternative:

  • local could be converted to a list, where the slashes /.../ are not presented to the user but added during option processing
  • this is unnecessary because the alias 'server' (DNS forwardings) is already a list.

and finally:

  • in dnsmasq add a list of lines to that the user may choose to populate.
  • they will be included verbatim in the generated dnsmasq.conf.
  • otherwise there is no way L/UCI can support all options of dnsmasq.
1 Like

regarding testing, i can't build openwrt or test right now, im very busy.

the solution i provided was not entirely right: i forgot to backup the symlink that marks the new service as enabled after a sysupgrade (/etc/rc.d/S18extra-dnsmasq-conf), so it would get disabled during sysupgrades.

i edited and fixed the original post now.