OpenWRT Configuration Hacks [Part 2]

by kacang bawang

In the previous post from this series we talked about customizing the dropbear startup scripts. This time we will direct our attention to dnsmasq, an all-in-one DNS-DHCP service. I will show you how to improve the configuration for a WAN/LAN/WIFI setup (as opposed to just WAN/LAN). We will get – hostnames such as router.lan, router.wifi and plain router for the router, and we will have clients get the appropriate client.lan or client.wifi name depending on which method they used to connect to the router.


Problem 1:
As stated previously, my configuration defines 3 interfaces: WAN, LAN and WIFI. I want to serve DNS and DHCP on the latter two. For DNS I want 2 domains: .lan and .wifi, such that each client obtaining an address by DHCP also gets a hostname.lan or hostname.wifi DNS name record, depending on whether they are using a wired or wireless connection to the router. The relevant option in /etc/config/dhcp is:

And the corresponding options in /var/etc/dnsmasq.conf config file (which is generated from /etc/config/dhcp) will be:

If left as above, all DHCP clients will get a hostname.lan DNS record. (Now you can ping your friends who came over to your house like this ping friends_computer.lan or like this ping friends_computer. The second (suffix-less) method works because of the option local, which makes the DNS server try .lan if no suffix is given). So, as you can see, this only allows for one domain to be handed out to the DHCP clients, whereas I want two.

Solution 1:
Once again we will convert the option domain to a list domain, such that we can specify multiple entries. Some additional work will be required to specify which ip-address range should get the .lan and which should get the .wifi. Our config file will look like this:

And the desired dnsmasq runtime configuration should contain the following as a result. The IP and netmask/CIDR come from the output of ifconfig.

Now we need to edit /etc/init.d/dnsmasq for our wishes to come true. I will include a link to a diffed view of the file at the end of the article (because the diff contains changes from here, as well as, Problem 2). For now I will describe what I did in words:

The dnsmasq/domain ‘option’ was converted to a ‘list’, and a list handling function was added that formed the config line (such as domain=lan,192.168.2.1/24) for each specified domain. This required a gnarly regexp to transform the Mask:255.255.255.0 to the CIDR notation. The source for the addr2cidr and cidr2addr functions is believed to be gentoo forums. I, myself, got it from the OpenWRT forums. Oh, and as a bonus here’s an explanation of the gnarly-ness. Awesome question-answer, right? But no, close, close, close :/

Problem 2:
I want to have the LAN and WIFI interfaces on the router to receive DNS names like this: router.lan and router.wifi. Furthermore, I wish to have plain router to resolve to either of the prior two, depending on whether the requesting machine is on LAN or WIFI. In other words, if I type ping router from a LAN machine, I should get router.lan/192.168.2.1, but not router.wifi/192.168.3.1.

By default, /etc/init.d/dnsmasq contains a block of code that adds own hostname if dnsmasq/option add_local_hostname is 1 or not present at all. This will result in the following lines being added to the runtime dnsmasq configuration in /var/etc/dnsmasq.conf:

There are two problems with the above. First, this only adds one of the two desired interfaces (no section for wifi). Second, the address option is being used incorrectly (this was fixed in Barrier Breaker 14.07, but since I am still on Attitude Adjustment 12.09 the fix must be introduced manually). address essentially makes a wildcard name record for the given domain. For example, a query to whatever.router.lan will be directed to 192.168.2.1. This is useful for blackholing advertisement domains for the entire home lan, such as *.doubleclick.net -> 127.0.0.1, but for what we want to do, this is incorrect. Non-existent subdomains should not be resolved. The correct option to use is host-record.

Solution 2:
Ok, let’s fix things. Rather than modifying the add local hostname code I chose to turn it off altogether by adding the following option to the /etc/config/dhcp

Instead, we will add to /etc/init.d/dnsmasq the dhcp_hostrecord_add() function from Adam Gensler’s patch, and will use it to manually add DNS records for our two interfaces. For this we will add two new sections to /etc/config/dhcp:

As a result, the following lines will appear in the runtime config:

Note also, that this gets rid of the ptr-record lines, but not their functionality. Reverse lookup will work, ie:

And there you have it. Now DHCP clients get proper suffixes added to their name, suffix-less names resolve to their correct .lan or .wifi counterparts, and the router itself has correct names for both local interfaces, which, when when used without a suffix will also correctly resolve to their .lan and .wifi counterparts.

Lastly, here are the before-and-after diffs for:
/etc/config/dhcp
/etc/init.d/dnsmasq
/var/etc/dnsmasq.conf — this one is formed automatically, but is nevertheless given to show the result of our manipulations.

And the files themselves can be found here.