header image

IMAGE: DNSCrypt-Proxy (logo part)

Did you know all internet addresses you browse on your Android mobile phone or tablet are resolved by Google DNS servers (8.8.8.8, 8.8.4.4, 2001:4860:4860::8888 and 2001:4860:4860::8844) as plain-text traffic, and due to that, your ISP may also know your browsing or application use habits?

The newest Android versions have feature known as private DNS. However, it accepts and uses only domain names instead of raw IP addresses, so I wouldn't trust the feature too much. Quite obviously you can use VPN. However, you are dependent on an external VPN provider service - and you hardly get useful DNS query logs at all.

So, no use either for built-in private DNS feature or VPN. What then? My answer: use a self-hosted DNS server with encryption support, running on your Android tablet or phone. Enforce every single DNS query by Android applications via that server. How? Keep reading. You need a rooted Android device.

Table of Contents


Foreword

Many applications on Android send data to network destinations ultimately unknown to you. However, it is possible to enforce all Android-originated DNS queries via your own Android-powered DNS server and check which internet addresses your Android applications actually connect to.

Not only that, but with the solution I give, your DNS traffic policy will also be enforced, so no matter what the application inner code logic says, your DNS server will always be used by force for domain name resolutions. No bypassing. One more thing: you will also have full ability to block suspicious internet addresses and inspect DNS query logs with timestamps. Every single one of them.

Issues in current Android DNS solutions

Traditionally, Linux systems use /etc/resolv.conf file and programs honor it when asking the system which DNS servers to use. Android has no such tradition and applications may implement different techniques for domain name resolution. To come around this dilemma, the ultimate solution is to operate one step deeper in OSI model in layers 1-3 with the help of iptables which is found on Android devices. Basically, we will use a simple NAT routing policy to enforce all DNS queries to your Android-powered DNS server. It means that every single DNS query will also fail when you turn the server off.

In addition to a self-hosted DNS server, I also recommend network traffic logging with the help of Wireshark/tshark and tcpdump. This helps you to get additional information not only about network traffic patterns but also to see whether your Android network traffic is actually encrypted or not.

About Android's built-in private DNS feature

There's a simple catch in private DNS feature, supported by newer Android devices. Very basic fact is that you shouldn't be able to use a domain name in private DNS input field. Why? Because that domain name needs to be resolved to a raw IP address by some internal process at first hand. So, before you could even use private DNS, the domain name you give to the input field must be resolved to an IP address by some internal Android process. Therefore, I don't trust private DNS feature approach.

DNSCrypt-Proxy

In this guide, I explain how to set up DNSCrypt-Proxy on Android. As the project GitHub page states, it is A flexible DNS proxy, with support for encrypted DNS protocols.

Prerequisites

  • A) Rooted Android phone

    • You need read-write access to the Android file system files (files of system partition, included in system.img)
      • This is for enforcing our DNS policy with system-wide iptables rules
  • B) Terminal application which supports git, wget & golang executables

  • C) Older Android phones: init.d support via init.rc files

    • .rc files may locate inside boot.img or at the file system path /system/etc/init, depending on your Android version and device
  • C) Newer Android phones: magisk (?) & existence of folder location /data/adb/service.d/

Guide

1) Install required Linux executables

Access your terminal application. I use Termux in my example.

  • Install packages: pkg install git wget golang

2) Get and compile DNSCrypt-Proxy from source code

Get DNSCrypt-Proxy source code and compile it on your Android tablet/phone. The process takes only a short while. Use my script below. On Android, create a new subfolder dnscrypt into your Termux home folder (full path: /data/data/com.termux/files/home/dnscrypt/). Save the script there.



3) DNSCrypt-Proxy configuration file

Use the following DNSCrypt-Proxy configuration file dnscrypt-proxy.toml

4) Short-living HTTP server for DNSCrypt-Proxy initialization

DNSCrypt-Proxy must load a pre-defined list file of public resolvers during its initialization phase. Either I don't know better way to do it but my best understanding is that DNSCrypt-Proxy can load such file only via HTTP/HTTPS protocols. I don't know if the situation has improved or file:/// URIs are supported but this is the way I do it:

I set up a short-living, local Python HTTP server on Android during DNSCrypt-Proxy initialization, and kill it after 10 seconds. Very serious trade off is that the server run in privileged TCP port 80. Due to that, the Python process must be run as real root. I have minimized the impact to give it only 10 seconds lifetime but I really should find a better solution for this step.

You see more details above in dnscrypt-proxy.toml file, section [sources], part urls = ['http://127.0.0.1/dnscrypt-resolvers/public-resolvers.md'] (line 597).

Since Python HTTP server works for 100% sure, I explain briefly how to set it up.

Make sure you have python executable in your Termux path. HTTP server is launched by issuing a short-living command (as root)

'su - root -c "LD_LIBRARY_PATH=\"/data/data/com.termux/files/usr/lib\" PATH=\"/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/bin/applets\" python -m http.server --bind 127.0.0.1 --directory /data/data/com.termux/files/home/localweb 80"'

This command is included in .bashrc file attachment below, as shown in step 5. It is automatically executed when you issue command dns in your Termux terminal application.

The web root directory, as you can see, is local Android directory /data/data/com.termux/files/home/localweb/. The directory contains a subdirectory dnscrypt-resolvers which has files minisign.pub, public-resolvers.md and public-resolvers.md.minisig, required by DNSCrypt-Proxy initialization.

You may have noticed line

export REMOTEFILES_DIR="${HOME}"/localweb/dnscrypt-resolvers

in the DNSCrypt-Proxy build script, step 2 above. When you build DNSCrypt-Proxy, the files are fetched from public web and placed into the localweb folder to be used by the Python HTTP process.

5) DNSCrypt-Proxy initialization scripts

So, how do you actually start DNSCrypt-Proxy process on Android?

I have a custom set of functions and aliases to be placed into .bashrc file.

The script set includes support for tor executable, if you have configured tor in Termux.

You can use the following content in your Termux's .bashrc file.

6) Enforcing iptables rules on Android

Depending on your Android system, put the following shell script either into /system/etc/init.d/ or /data/adb/service.d/ folder with 0700 permissions (owner root:root).

Read-only filesystem issue: You may need to re-mount the Android file system (sudo mount -o remount,rw / or tsudo mount -o remount,rw /), or use TWRP recovery to put the shell file in the correct place as explained above.

Results: your own Android DNS server in action

post image
DNSCrypt-Proxy running on Android. A lot of errors about missing certificate hashes (I really should update some files here). However, the DNS server is still functional.
post image
Although Termux nslookup tool claims DNS server used for name resolution is 8.8.8.8, the results actually show otherwise. We have enforced use of the local DNSCrypt-Proxy server in iptables NAT rules. Our DNS server blocks IPv6 AAAA DNS queries and resolves some suspicious domains as 0.0.0.0.
post image
DNSCrypt-Proxy offers us tools to analyze and get every single DNS query with a timestamp made by any Android application. Not only that but we can block (CLOAK) these domains, too.
post image
When we enforce all DNS queries to our DNSCrypt-Proxy server, and we turn the server off, all DNS queries by Android applications fail. There's very little applications can do to circumvent that without custom implementations or non-standard approaches.

You can also fetch Android's network traffic with tcpdump or WireShark/tshark, and see that all DNS queries really are encrypted as they should be now.

Additional steps

You might want to check out my DNS sinkhole (GitHub) scripts to auto-generate a cloaking list of suspicious and malicious domains for DNSCrypt-Proxy. I use it, and have over 240 000 domains cloaked (resolved as 0.0.0.0).

Put generated dnscrypt.cloaking.txt rule file into /data/data/com.termux/files/home/dnscrypt-android/ folder and restart the DNS server by issuing dns command in Termux terminal.

Some applications ignore DNS

Applications such as Whatsapp and Telegram seem not to use Android's DNS service, or at least TCP/UDP ports 53 as they can still get network connection even if we turn our DNS server off.

Remove Google DNS referrals from Android source code

Android source code has referrals to Google's DNS servers and NTP server time.android.com. To patch them out, use my patch file patch_localhost-dns_ntp_gps.patch for AOSP 11 (Lineage OS 18.1).

The patch file has couple phone-specific files for Samsung mobile phone but most of the files are just for AOSP.