( From The DNS Privacy Project ) DNS-OVER-TLS on OpenWrt/LEDE FEATURING UNBOUND GETDNS and STUBBY

Dear EricLuehrsen,
Thanks for your insights and knowledge. See here -
Proper Setup For New Native Unbound DNS-Over-TLS Feature Starting With UNBOUND 1.7.1
and here:
https://torguard.net/forums/index.php?/topic/1426-lede-openwrt-proper-setup-for-new-native-unbound-dns-over-tls-feature-starting-with-unbound-171/
So I agree and am aware; however, I still prefer GETDNS and STUBBY as they are actively being developed
and maintained. Planning indicates that they will only get better and more secure with time. UNBOUND and GETDNS are both developed and maintained by https://www.nlnetlabs.nl/
That being said, why would NLnet Labs be actively implementing and developing GETDNS and StUBBY if UNBOUND is adequate on its' own for comprehensive DNS PRIVACY ? That is something for you and others to research, ponder and resolve when choosing your preferred method of implementing and deploying DNS OVER TLS with UNBOUND.

Peace and God Bless,

directnupe

NSD (authoritative) and Unbound (recursive) are high traffic servers. Unbound is optimized to handle being a public recursive DNS server. NSD serves a few root-servers. GetDNS is an application level library to integrate DNS (easier). We could consider traffic cameras, weather stations, and other stand alone appliances with a singular connection to a wireless ISP. Stubby is a reference forwarding implementation using GetDNS, and it could replace dnsmasq at the end user device. Depending on your use case including user volume and compute resources, you need to pick the right tool.

Dear Eric,
WOW ! and I am not being sarcastic - thanks for your analysis of all the landscape regarding the various components and options available regarding DNS. Do you think that configuring UNBOUND in the manner where one uses the - tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt method we discussed earlier is as fast ( or faster ) and as safe ( or safer ) than GETDNS and STUBBY with UNBOUND?
In any event I really learned a lot from you and I appreciate your feedback and clarifications. I am really just somewhat of a hobbyist and novice.

God Bless and Peace Eric,

Derek

I only provided a quick compare on NLnet Labs "products." It would seem with NLnet Labs, they all should at least challenge each other during testing. For example drill (ldns) has been used to test DNSSEC in other server products, and it found errors with them or itself. They actually promote the benefit of code diversity in that link.

I think I have this working well now by installing only unbound, unbound-control and luci-app-unbound. No stubby, no getdns, no odhcpd.

I first tried according to the Cloudflare blog above, replacing dnsmasq with unbound+odhcpd, but burned a whole evening trying and failing to get it to resolve local DHCP client names. I know my way around dnsmasq pretty well, and really didn't like the idea of having to learn odhcpd WHILE fussing with how UCI/LUCI map their options into odhcpd configuration.

Then I saw the "Serial dnsmasq" section of the unbound+luci documentation here:

Once I uninstalled odhcpd and restored dnsmasq, local name resolution started working again and the parameters on the Network > DHCP and DNS page in luci of course began working as advertised again.

Then I configured DNSmasq to use unbound as its upstream as described on that github link. unbound listens on 1053, dnsmasq on 53, and LAN resolution goes client -> dnsmasq(:53) -> unbound(:1053) -> HTTPS encryption -> cloudflare

I also had to change the WAN interface advanced settings to disable "Use DNS servers advertised by peer" and specified 127.0.0.1 (dnsmasq) as the local resolver (and for the wan6 interface the same with loopback address ::1).

No more plaintext DNS queries are going out, so I took the added measure of adding a couple firewall rules (Network > Firewall > Custom Rules) to prevent leaks:

#Block plaintext DNS from router
iptables -I OUTPUT -o eth1 -p udp --dport 53 -j REJECT
iptables -I OUTPUT -o eth1 -p tcp --dport 53 -j REJECT

#Block plaintext DNS from other interfaces
iptables -I FORWARD -o eth1 -p udp --dport 53 -j REJECT
iptables -I FORWARD -o eth1 -p tcp --dport 53 -j REJECT

I like the way it's working so far. I didn't have to monkey with stubby or odhcpd, and won't have to worry about the DNS and DHCP configuration parameters functioning differently than the typical out-of-the-box lede/dnsmasq experience.

I might write up a step-by-step if there's enough interest? What I ended up doing felt simpler than the cloudflare blog post and a LOT simpler than the process in the original post here.

There is the OpenWrt wiki, which suggests serial over parallel, but the github README would suggest the opposite from my read. Also a little syntax fixup.. But yes, dnsmasq and unbound seems simple and effective; a wee less brittle as it were.

Serial is easier to configure and works well for a few users with a few devices. When its applied to low cost hardware with multiple transient users dnsmasq needs to answer DHCP, dnsmasq and Unbound are resolving, and dnsmasq and Unbound are storing copies of the cache. If you want dnsmasq to confirm DNSSEC for devices ... not so good. Parallel allows devices to get their frequent internet resolution directly from Unbound, and stresses the router less. Unbound only looks to dnsmasq and less often when intranet resolution is required. Neither option is "better" but rather possibilities to handle different situations.

Right... having looked over a few more articles in the wiki and elsewhere, and the meat in the middle of this thread, I can see that this simple implementation I went with isn't nearly as secure as the one kicking off the thread.

Still, I set out with two goals here, 1) circumventing my ISP's simple browser hijacking and 2) obscuring my activity to reduce my ISP profiling my usage.

This is on a home network with just a half-dozen wired servers and maybe a dozen other gadgets that run fairly quiet on the network, so I'm not worried about dnsmasq's scalability at this point. (Especially after splurging on this WRT3200ACM with dual cores and more RAM than I need.)

If anyone else is in a similar boat and finds the original proposal up top too daunting, the basic serial proxying over HTTPS through unbound is a solution I'd suggest considering first.

LEDE's firewall table has quite a number of chains, among them are custom chains meant for such custom rules. They are denoted with the comment suffix "/* !fw3: Custom <input/output/forward> rule chain */"

If you'll like to avoid potential conflict of custom rules with the ones in the firewall config file, those above can be added into the "output_rule" and "forwarding_rule" chains.

That makes sense. I'll use those chains.

Perhaps the comment lines in LEDE's default /etc/firewall.user file ought not to say "put custom rules into the root chains e.g. INPUT or FORWARD"? I wouldn't have done it that way if it didn't explicitly suggest it.

Those custom chains (for custom insertions) are kinda "documented" here in the flow tables:

https://openwrt.org/docs/guide-user/firewall/firewall_configuration#packet_flow

But I do agree they can be made clearer.

Users can write UCI firewall for forward zones easily. To prevent all individual device connections and force DNS through the router, block LAN-WAN forwards for 53, 853, and maybe 5353. UCI strangely has "to device" easy rules but not "from device."

UCI

config rule
	option name 'Block-Public-DNS'
	option enabled '1'
	option src 'lan'
	option dest 'wan'
	option dest_port '53 853 5353'
	option proto 'tcpudp'
	option family 'any'
	option target 'REJECT'

Remaining custom rules

#Block plaintext DNS from router
iptables -I OUTPUT -o eth1 -p udp --dport 53 -j REJECT
iptables -I OUTPUT -o eth1 -p tcp --dport 53 -j REJECT

I suppose the idea is that we need to trust all the services on the router that are in any way capable of crafting packets, which is hard to argue with in principle. I tried when I worked for another company that made a linux-based router distro with the same limitation. The defense-in-depth argument always lost to the "most of the people who try it are going to shoot themselves in the foot" argument. (Not to mention the "think of the poor QA folks!" argument...)

I threw those output rules in to monitor for my own misconfigurations more than anything else. The counters are still sitting at zero for both rules, I'm sure they'll stay at zero forever unless I fiddle with the configuration some more and do something wrong or pull in an updated package with a new bug.

I would still like to know why unbound is needed at all. What is wrong with using dnsmasq and Stubby together to ensure DNS goes out over TLS?

If you use OpenWrt (master snapshot) then Unbound comes with UCI/LuCI to configure Forward-TLS. The easiest setup then is add Unbound and CA-Bundle to base OpenWrt. Have dnsmasq forwad to Unbound as if Unbound were the ISP upstream. After some rest period the UCI upgrades may backport to 18.06.

But, the stubby FAQ states:

"However at the moment Unbound does not have all the TCP/TLC features that Stubby has for example, it cannot support 'Strict' mode, it cannot pad queries to hide query size and it opens a separate connection for every DNS query (Stubby will re-use connections)."

So it seems to me that dnsmasq+stubby would perform better than dnsmasq+unbound. No?

Also, how i know, unbound in openwrt builded without tcp fast open.

So it seems to me that dnsmasq+stubby would perform better than dnsmasq+unbound. No?

Yes but stubby does not support (l)uci.

The defaults from the Makefile:

CONFIGURE_ARGS += \
        --disable-dsa \
        --disable-gost \
        --enable-allsymbols \
        --enable-tfo-client \
        --enable-tfo-server \
        --with-libexpat="$(STAGING_DIR)/usr" \
        --with-ssl="$(STAGING_DIR)/usr" \
        --with-user=unbound \
        --with-run-dir=/var/lib/unbound \
        --with-conf-file=/var/lib/unbound/unbound.conf \
        --with-pidfile=/var/run/unbound.pid

Okey. It was added couple months ago.

I have a working configuration of Stubby+Dnsmasq (no Unbound), running on an old router (4/32MB), v18.06.0, no Luci, everything configured via console and stubby is installed into RAM upon boot, if anyone's interested. :slight_smile:

1 Like