[Magisk] ashketchum:
Update (8 August 2023): New module added that uses Android's "Private DNS" feature instead of the iptables rules (which would not have worked with IPv6 anyway). Previously when I was trying it with generated certificates it was not working. But then I tried to generate the certificates similar to the ones that Adguard uses and it started working. Then I tried using ECDSA certificates instead (just for fun) and it continued to work. So this module generates a custom root CA certificate that signs the certificate used by Unbound for it's DNS-over-TLS port. And then configures the "Private DNS" feature to use "localhost". Apparently the feature was added in Android 9, so I made the module installable on Android 9+ only. New binaries compiled with API level set to 28 also. Anyway, remove the old module before installing this one (Unbound-v1.17.1-Android9.zip) or check "unbound.conf.new" in "/data/adb/unbound/" after installation and change your configuration accordingly.

Certificate used by Unbound will have one year validity so just reinstall the module to generate a new one. Previously I tried with long validity certificate. Not sure if it was not working because of that. 🤷‍♂️

I made this magisk module for myself and have decided to share it here. Binaries in the module are for arm64 only though.

Anyway, I got the idea from this magisk module - https://github.com/bluemeda/dnscrypt-proxy-magisk

There is also this - https://github.com/smarek/android-unbound-dns - but it is no longer being maintained it seems.

I made it mainly because I switched to using ED448 DNSSEC algorithm on my domain and later noticed that various public resolvers were failing the ED448 test at https://www.rootcanary.org/test.html. I seem to recall seeing the test pass at https://ed448.no, and that is why I decided to switch. But later noticed that multiple resolvers were failing the test.

With this magisk module installed, DNSSEC validation is done on your device by Unbound (https://www.nlnetlabs.nl/projects/unbound/about/) so you can even use public resolvers which do not support DNSSEC validation at all. You know, due to all the controversy surrounding it, even though it has been many years now. Like OpenDNS for example. They were strong opponents of DNSSEC if I recall correctly and were favoring DNSCrypt instead even though it is supposed to be something totally different from what I understand anyway. Oh wait, never mind. Just recalled that OpenDNS does not support DoT (DNS over TLS) - https://adguard-dns.io/kb/general/dns-providers/ . Unbound only supports DoT forwarding as of now. Once again from what I understand. I saw mention of DoH in their documentation and assumed that it did, but it turned out to be for incoming connections only.

Of course, you can even skip using public resolvers and let your device do the resolving. Edit the unbound.conf file in "/data/adb/unbound/unbound.conf" after installation and change (or remove) the "forward-zone:" section according to your needs. You can also change the entire configuration if you want after going through the Unbound documentation available here - https://unbound.docs.nlnetlabs.nl/en/latest/

Anyway, enjoy! 👍

Edit (2 August 2023): Thought I should mention that I found out after making this post that OpenDNS does support DoT now (since January 2022). The information on the Adguard page is outdated. So you can indeed use this module with OpenDNS also. Example configuration change for OpenDNS (/data/adb/unbound/unbound.conf):

forward-zone:
name: "."
forward-first: no
forward-tls-upstream: yes
forward-addr: 208.67.222.123@853#familyshield.opendns.com
forward-addr: 208.67.220.123@853#familyshield.opendns.com

And I thought I should also mention that additional changes are required if you want your device itself to do the resolving instead of forwarding. You will have to remove the iptables rules from the service.sh file and use some other configuration to ensure that your device uses Unbound. For example, if you are using Adguard, you can simply add the IP address and port in the DNS filter section. You can also use one of those DNS changer apps from the Play Store to set your DNS to 127.0.0.1. You may have to set the listen port in unbound.conf to 53 though. I am not sure if these apps support custom ports also. Adguard does support custom ports though, so you can just add 127.0.0.1:5354 and it will work.