DNS resolution in the HD/HDR-Fox T2

/df

Well-Known Member
This post (with its thread) is to document what we know about DNS resolution in the HD/HDR-Fox T2 systems.

At the root is the uClibc resolver. In theory this behaves like the glibc resolver in desktop/server Linux, as described in the resolv.conf manual page, but, libc being uC, the theory is approximate.

The uClibc version in use doesn't correspond to any version in the uClibc source code repository. Broadcom devs abstracted a now defunct branch that implemented NPTL multi-threading corresponding to the 0.9.29 trunk version, but the resulting resolver code in uClibc-nptl-0.9.29-20070423.tar[.gz] from the Humax Open Source download page (also find it at the Broadcom GitHub site) is significantly different from both the 0.9.29 trunk version and also from the first trunk release with NPTL (0.9.32, 2012-06). The busy commit log is a bit concerning. Only the main options described for resolv.conf are supported.

Using the libc resolver, a host DNS lookup queries the first IP address listed as nameserver <IP> in /etc/resolv.conf, trying each nameserver entry in turn until one doesn't time out. This is also true for the uClibc resolver: however, the "rotate" resolv.conf option, which would start with each listed name server in turn, isn't understood (only "nameserver", "domain", and "search").

However, in normal operation the uClibc resolver isn't the only component that's used in resolving DNS addresses. The Humax devs installed the dnsmasq, v2.56, utility as a caching DNS proxy (the build configuration also supports TFTP). They forgot to tell the lawyers, though, as dnsmasq isn't offered from the Humax Open Source page with other GPL sources: surely Humax didn't relicense it? Legality aside, dnsmasq is expected to be running before the set-top program is launched, being launched by the /etc/init.d/S41dnsmasq startup script.

With dnsmasq listening on 127.0.0.1 and that address listed as the first nameserver entry in /etc/resolv.conf, a host DNS lookup goes to dnsmasq, and only to any other listed servers if that times out. dnsmasq in turn will return a reply if it has a valid cached or configured answer to the query, or forward the query to each of the next listed servers until one doesn't time out. There's some dnsmasq configuration in the read-only /etc/dnsmasq.conf:
Code:
# try each name server in turn, instead of using dnsmasq's health metric
strict-order
# receive DNS lookups 
listen-address=127.0.0.1
# DNS and TFTP only
no-dhcp-interface=eth0
no-dhcp-interface=wlan0
# don't read /etc/hosts
no-hosts
But /etc/resolv.conf should also be read-only, so how do the name servers get added? In fact this read-only flash file is a symbolic link to /var/lib/humaxtv/resolv.conf, which is writable.

The Humax set-top program contains a network configuration module, whose UI is accessed by Menu>Settings>System>Internet Setting, which probably assumes that there is only one actual LAN interface, either eth0 or wlan0. If the interface is configured for DHCP, the DNS setting (list of name server(s)) can be provided by the DHCP server; otherwise it has to be entered in the "Configure LAN" page. The set-top program writes these entries into /etc/resolv.conf, replacing any previous contents (which dnsmasq will have been using so far):
Code:
search bad
nameserver 127.0.0.1
nameserver <DNS setting>
...
nameserver 208.67.222.222
nameserver 208.67.220.220
nameserver 8.8.8.8
nameserver 8.8.4.4
The first line causes a lookup for an unqualified hostname XXX to be interpreted as looking up XXX.bad, and therefore, as expected by the Humax devs in 2010, returning non-existent domain. Now that almost any old junk can be a TLD, "search invalid" should be used instead.

The second line forces resolution by a local DNS server (such as dnsmasq), if available.

The next lines, which may be repeated, list the name servers configured manually or by DHCP.

Finally, if DHCP is in use, the udhcpc action script /usr/share/udhcpc/default.script adds the local IP address for dnsmasq and two well-known server addresses for OpenDNS and two more for Google's DNS. This seems like overkill, but could have saved Humax some support calls due to badly configured home routers setting invalid DNS server(s) by DHCP, or due to bad manual DNS addresses (Problem Existing Between Couch And Screen). Although the uClibc resolver, like traditional libc resolvers, only looks at the first 3 name servers, dnsmasq doesn't have such a limit.

The DNS Address value shown on the "Configure LAN" page is (apparently) the address from the first nameserver entry in /etc/resolv.conf that is not 127.0.0.1.

dnsmasq in the configured version polls /etc/resolv.conf to get the latest name server list; recent versions know how to use libinotify. The program ignores any instance of its "listen-address" in the returned list and uses the list according to the specified "strict-order" option (rendering the long list of DNS servers irrelevant). In this way the same resolv.conf can be used regardless of whether dnsmasq is running.

The above all applies to both stock and custom FW, but working it out or changing its behaviour requires the custom FW.

The dnsmasq binary, startup script and configuration file are stored in the read-only root filesystem. Various options exist for modifying its behaviour:
  1. to change the configuration, you can create a new configuration file, bind-mount it over /etc/dnsmasq.conf, and restart dnsmasq; generally any option that could be specified on the dnsmasq command line can be put in the configuration file using the long option name without its -- prefix, as shown in an example below;
  2. to run dnsmasq in a more sophisticated way, create a new startup script in /mod/etc/init.d to implement the desired behaviour: as part of its 'start' action, the script should stop the built-in dnsmasq before launching dnsmasq again, and vice versa;
  3. you can build a new version of dnsmasq: eg, I tried 2.82-2-ga2a7e04 from the GitHub site, which could be built on-box with some header file munging to deal with missing IPv6 definitions; then run it using method 2 above.
One interesting configuration change is to add the -8 - -q command-line options, or equivalently the configuration options:
Code:
log-facility=-
log-queriesl
This causes dnsmasq to log all queries to stderr, so you can see what DNS names are being used by the system, eg by JS loaded into the set-top program's browser module by a TV Portal app.
 
Last edited:
The DNS Address value shown on the "Configure LAN" page is (apparently) the address from the first nameserver entry in /etc/resolv.conf that is not 127.0.0.1.
I don't understand this. The DNS address shown in my LAN configuration is the forwarding port on my router (as is the Gateway), and the router has an external DNS setting. Is this too simplistic?
 
I don't understand this. The DNS address shown in my LAN configuration is the forwarding port on my router (as is the Gateway), and the router has an external DNS setting. Is this too simplistic?
No.

I think your situation is typical, though it would be interesting to see what's in your /etc/resolv.conf. It's probably like this, if DHCP is in use:
Code:
search XXX
nameserver 127.0.0.1
nameserver <your-router-IP>
nameserver 208.67.222.222
nameserver 208.67.220.220
nameserver 8.8.8.8
nameserver 8.8.4.4
In particular it would be interesting to know if the XXX is present, and what string XXX is; also whether the router IP is repeated.

As the router IP is the first nameserver entry that isn't 127.0.0.1, that's what is shown in the on-screen UI. If there isn't one you get 0.0.0.0.

Normally your box will resolve a previously unresolved DNS name by querying the local dnsmasq, which in turn will query the DNS on your router, and that will query one of the external servers that you have configured.

If the local dnsmasq isn't working, the router's DNS will be queried directly.

If the local dnsmasq is working but the router's DNS isn't (either the server on the router, or all the configured external servers), the external servers listed in resolv.conf will be used in turn.

If neither the local dnsmasq nor the router's DNS is working, the third server in resolv.conf (OpenDNS in the example) will be tried (because the uClibc resolver stores only 3 servers, and the first two are dead).
 
Jeez, it's so complicated. I think the problem is that I work from the Ladybird Book of Understanding How the Internet Works when actually that's a highly simplified version just to get the basic concepts over. What I understand from what you say is there is a hierarchy of opportunities for name resolution, and it is possible to intercept the resolution locally whereas normally all resolutions would be handled by a server on the Internet:

Google for a URL; send DNS request for URL resolution to IP address; send www query to IP address.​

Does "masq" mean anything (the "dns" bit is self-evident)? Is "masq" a homophone for "mask" by any chance?

Here's my resolv.conf (from my HDR1 - which is connected to the router by Ethernet via HomePlug), which I think is going to surprise you:
Code:
nameserver 192.168.1.254
nameserver 208.67.222.222
nameserver 208.67.220.220
...and this is identical across all my units (another HDR by HomePlug, a HD by HomePlug, and a HDR by WiFi dongle). My modus operandum is to run a DHCP and then switch to manual.

Maybe I have not factored in that I am not actually running iplhack - would that explain the difference?

FWIW, I have the router set to 1.1.1.1 (primary) and 8.8.8.8 (secondary) - which I vaguely recall I might have done myself rather than "get automatically from ISP".

As an aside, while I was digging in the router control panel for the DNS resolution path, I found this and I am curious to know what it means:

1609318723409.jpeg
...bearing in mind the gateway is 192.168.1.254, which does not appear in the table at all!
 
The router runs its own DNS server (probably another instance of dnsmasq) which responds to DNS queries on the router's ethernet and WiFi interfaces and forwards unknown requests to the upstream servers 1.1.1.1 or 8.8.8.8. The DHCP server sends the IP address of the router's internal connection as a DNS server 'option' so that devices on the local network can include it in their resolv.conf (or equivalent).

The masq in 'dnsmasq' is a shortened form of masquerade.

A specific entry in the gateway column is not needed for 192.168.1.254 in the router's routing table because the 192.168.1.0/24 network is directly accessible using the IP and netmask. I am not sure why it appears to have two tables 'Main' and 'LAN'.
 
1.1.1.1 is the Cloudflare/APNIC DNS server.

The thing to understand about DNS is that it's a hierarchical distributed database. The two adjectives determine how it works. The hallowed root servers know about the top-level domains and who is authoritative for the next levels, and so on down.

Your query for www.example.com (if example.com were not a reserved domain) is conceptually forwarded through a chain of servers until it reaches a server that claims to be authoritative for example.com. It's a bit like getting some specialist home maintenance done in the olden days: you ask the odd-job man; he can't do it but has friend who might; the friend isn't exactly the right chap for the job, but has a friend ...

As that would be too slow, DNS makes use of time-limited cached data. Servers like those offered by Cloudflare, Google and OpenDNS probably keep data on the authoritative servers for all the second-level zones as well as a giant cache of actual results (in the case of Google, spidering generates a constant stream of results). But, like turtles, caching goes all the way down to each network endpoint: if you use your ISP's DNS, that caches answers; if your home router has a DNS server, that caches answers; your Unix-like network endpoint typically has a DNS server (eg dnsmasq) that caches answers.

This overview is pretty good, but ignore any references to Active Directory. This series of blog posts shows how the ideas are realised in a typical Linux desktop (of 2018), and can be compared with the corresponding description for HD/HDR-Foxes in post #1.

The lunatics who have taken over the WWW asylum are promoting a new DNS access protocol in which DNS queries and replies are carried over HTTPS. This won't affect HD/HDR-Foxes unless it leads to traditional DNS being discontinued. As always, 2038 is a more likely deadline.
 
...
Here's my resolv.conf (from my HDR1 - which is connected to the router by Ethernet via HomePlug), which I think is going to surprise you:
Code:
nameserver 192.168.1.254
nameserver 208.67.222.222
nameserver 208.67.220.220
...and this is identical across all my units (another HDR by HomePlug, a HD by HomePlug, and a HDR by WiFi dongle). My modus operandum is to run a DHCP and then switch to manual.
This looks consistent with a manual setup inherited from a DHCP installation: maybe a long time ago, as the Google DNS addresses aren't there, or perhaps the set-top program trims it to 3 name servers because of the historical libc limit.
Maybe I have not factored in that I am not actually running iplhack - would that explain the difference?
...
No, because iplhack just injects one spoof answer into the normal processing chain.
 
The set-top program writes these entries into /etc/resolv.conf, replacing any previous contents (which dnsmasq will have been using so far):
search bad
...
The first line causes a lookup for an unqualified hostname XXX to be interpreted as looking up XXX.bad, and therefore, as expected by the Humax devs in 2010, returning non-existent domain.
In my case, it reads "search lan" because on the DHCP server I have set the domain to "lan" (option 15?) and the domain search to "lan" (option 119), and this seems to keep the various Linux (& Windows) clients/resolvers happy (they weren't after some upgrade or other when I had no domain).
 
Having looked at the telnet command interface of the antique Thomson router, I can't see any sign of those DHCP options being populated, so maybe the "bad" domain suffix is the default set by the Humax settop program.
 
maybe the "bad" domain suffix is the default set by the Humax settop program.
I can't see any sign of it on either udhcpc or humaxtv using strings and grep.
I don't have time to p155 about with Wireshark currently...
 
Also, the uClibc DNS server selection can be seen at https://github.com/Broadcom/stblinu...Clibc-nptl-0.9.29-20070423/libc/inet/resolv.c:
  • l. 718: static variables are initialised: ns is the index into the array of servers read from resolv.conf (in file order); id is the query id;
  • l. 750ff: variables local to the lookup function are copied from ns and id;
  • l. 762ff: the id is incremented modulo 65536 and the server address is set;
  • l. 803ff: it tries to open a socket with a maximum number of retries;
  • l. 822ff: it tries to connect to the socket with a maximum number of retries, or (network unreachable) it tries the next server;
  • l. 957ff: ns and id are copied back to the static variables if the lookup succeeded;
  • l. 963ff, 975ff: for various failure cases, the next server address is tried.
So if, say, dnsmasq didn't return a result, the resolver would go on to the next DNS server, and all the other servers in resolv.conf would have to fail before dnsmasq would be used again.

Further, it appears that the uClibc resolver reads resolv.conf once per process and only re-reads it if no DNS servers were specified; possibly also if the network is re-connected. dnsmasq would normally re-read resolv.conf if its modification time has changed.
 
Last edited:
I can't see any sign of it on either udhcpc or humaxtv using strings and grep.
I don't have time to p155 about with Wireshark currently...
I agree on humaxtv, but consider offset 0x4fa9c of /sbin/udhcpc, right in the middle of a load of text constants:
Code:
0004fa90  75 00 00 00 25 73 3d 00  25 6c 64 00 62 61 64 00  |u...%s=.%ld.bad.|
 
Back
Top