I run the highly popular and lightweight dnsmasq DNS forwarder and DHCP server program on numerous embedded devices. One of the cool things you can do with dnsmasq is something called split DNS (some people call it split-brain DNS or split-horizon DNS). If you don’t know what it is, go check out the wikipedia story.
To implement split DNS with dnsmasq, you use the -S or –server option. Here is the description from the dnsmasq man page:
S, –local, –server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
Specify IP address of upstream servers directly. Setting this flag does not suppress reading of /etc/resolv.conf, use -R to do that. If one or more optional domains are given, that server is used only for those domains and they are queried only using the specified server. This is intended for private nameservers: if you have a nameserver on your network which deals with names of the form xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving the flag -S /internal.thekelleys.org.uk/192.168.1.1 will send all queries for internal machines to that nameserver, everything else will go to the servers in /etc/resolv.conf. An empty domain specification, // has the special meaning of “unqualified names only” ie names without any dots in them. A non-standard port may be specified as part of the IP address using a # character. More than one -S flag is allowed, with repeated domain or ipaddr parts as required.
Here is an example of how to use that option:
The above example basically says “If the DNS client is looking up the IP address of a host on the domain
internal.somecompanyname.com, forward the request to the DNS server at address 192.168.1.69, otherwise forward the request to the default DNS server” (the default DNS server is typically your ISP’s DNS server). In other words, DNS resolution is split between the two servers, depending on the domain name of the host name being queried.
A few days ago I was preparing a LinkSys WRT54GL router for a small office. Because the office’s requirements exceeded what the stock LinkSys firmware could do, I reflashed the router with the Tomato USB third party firmware (version 1.28.8754 ND vpn3.6, in particular).
I configured split DNS like my example above but when I tried to do a DNS lookup for
nslookup returned the following error:
*** No address (A) records available for foo.internal.somecompanyname.com
After reading through the dnsmasq man page, I discovered the problem. By default, the version of Tomato I was running enables the setting “Prevent DNS-rebind attacks” in the web interface. The “Prevent DNS-rebind attacks” checkbox corresponds to the
stop-dns-rebind setting in the dnsmasq config file:
Reject (and log) addresses from upstream nameservers which are in the private IP ranges. This blocks an attack where a browser behind a firewall is used to probe machines on the local network.
Since a query for a host such as foo.internal.somecompanyname.com returns a private IP address, the query response was being rejected by dnsmasq. One possible solution is to uncheck this box. However, I think a better and safer solution is to add this setting to the config file:
Here is a description of that setting from the dnsmasq man page:
Do not detect and block dns-rebind on queries to these domains. The argument may be either a single domain, or multiple domains surrounded by ‘/’, like the –server syntax, eg. –rebind-domain-ok=/domain1/domain2/domain3/
rebind-domain-ok setting is way better than turning off
stop-dns-rebind because it limits the possibility of DNS rebind attacks to just certain domains rather than all domains. In other words, we don’t have to throw out the baby with the bath water.
After making the dnsmasq configuration change, DNS lookups of internal hosts worked fine with both nslookup and dig.
I hope that helps someone else. Leave a comment!