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.
1#!/system/bin/sh
2 3exportROOTDIR="${HOME}"/dnscrypt
4 5exportGOPATH="${ROOTDIR}"/gopath
6 7exportDNSSRC="${ROOTDIR}"/dnscrypt-proxy
8exportDNSSRC_LINK="${GOPATH}"/src/dnscrypt
910exportDNSDEST="${HOME}"/dnscrypt-android
1112exportEXECNAME="dnscrypt-proxy"13exportTOUCHNAME="README"1415exportREMOTEFILES_DIR="${HOME}"/localweb/dnscrypt-resolvers
1617if[[ ! -d "${DNSSRC}"]];then18 git clone https://github.com/DNSCrypt/dnscrypt-proxy
19#else20# cd "${DNSSRC}"21# git pull22fi2324if[[$? -ne 0]];then25echo"Something went wrong. Refer to output and documentation for help."26exit127fi2829cd"${ROOTDIR}"3031rm -rf "${DNSSRC_LINK}"3233mkdir -p "${DNSSRC_LINK}"34ln -sfn "${DNSSRC}""${DNSSRC_LINK}"3536cd"${GOPATH}/src/dnscrypt/dnscrypt-proxy/dnscrypt-proxy/"37if[[ -f main.go ]];then38echo"Compiling DNSCrypt Proxy executable. Please wait..."39 go build -ldflags="-s -w"40echo"Done"41fi4243if[[$? -ne 0]];then44echo"Something went wrong. Refer to output and documentation for help."45exit146fi4748if[[ -f "${EXECNAME}"]];then4950echo"Finalizing setup"5152 mkdir -p "${DNSDEST}"5354 mv -f "${EXECNAME}""${DNSDEST}/"5556 mkdir -p "${DNSDEST}/EXAMPLE_CONFIGS"5758echo"Move these files into: ${DNSDEST}59Remove example part from their names.
60You can use DNSCrypt Proxy after proper configuration.
61" >> "${DNSDEST}/EXAMPLE_CONFIGS/${TOUCHNAME}"6263for f in $(find . -type f -iname "*txt" -or -iname "*toml" -or -iname "*md");do64 cp "${f}""${DNSDEST}/EXAMPLE_CONFIGS/"65done6667echo"Finished. Compiled DNSCrypt Proxy is at: ${DNSDEST}"6869fi7071echo"Updating domain name server information..."7273for f in \
74"https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md"\
75"https://download.dnscrypt.info/resolvers-list/v3/minisign.pub"\
76"https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md.minisig"\
77;do78filename=$(echo${f}| sed -r 's/.*\/(.*)$/\1/')79 wget ${f} -O "${REMOTEFILES_DIR}"/${filename}8081if[[$(stat -c %s "${REMOTEFILES_DIR}"/${filename}) -eq 0]];then82echo"Couldn't download file ${f}. Aborting"83break84fi8586done
3) DNSCrypt-Proxy configuration file
Use the following DNSCrypt-Proxy configuration file dnscrypt-proxy.toml
1############################################## 2# # 3# dnscrypt-proxy configuration # 4# # 5############################################## 6 7## This is an example configuration file. 8## You should adjust it to your needs, and save it as "dnscrypt-proxy.toml" 9## 10## Online documentation is available here: https://dnscrypt.info/doc 11 12 13 14################################## 15# Global settings # 16################################## 17 18## List of servers to use 19## 20## Servers from the "public-resolvers" source (see down below) can 21## be viewed here: https://dnscrypt.info/public-servers 22## 23## The proxy will automatically pick working servers from this list. 24## Note that the require_* filters do NOT apply when using this setting. 25## 26## By default, this list is empty and all registered servers matching the 27## require_* filters will be used instead. 28## 29## Remove the leading # first to enable this; lines starting with # are ignored. 30 31# server_names = ['scaleway-fr', 'google', 'yandex', 'cloudflare'] 32 33 34## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6. 35## Example with both IPv4 and IPv6: 36## listen_addresses = [] 37 38listen_addresses=['127.0.0.1:5533'] 39 40 41## Maximum number of simultaneous client connections to accept 42 43max_clients=250 44 45 46## Switch to a different system user after listening sockets have been created. 47## Note (1): this feature is currently unsupported on Windows. 48## Note (2): this feature is not compatible with systemd socket activation. 49## Note (3): when using -pidfile, the PID file directory must be writable by the new user 50 51# user_name = 'nobody' 52 53 54## Require servers (from static + remote sources) to satisfy specific properties 55 56# Use servers reachable over IPv4 57ipv4_servers=true 58 59# Use servers reachable over IPv6 -- Do not enable if you don't have IPv6 connectivity 60ipv6_servers=false 61 62# Use servers implementing the DNSCrypt protocol 63dnscrypt_servers=true 64 65# Use servers implementing the DNS-over-HTTPS protocol 66doh_servers=true 67 68 69## Require servers defined by remote sources to satisfy specific properties 70 71# Server must support DNS security extensions (DNSSEC) 72require_dnssec=true 73 74# Server must not log user queries (declarative) 75require_nolog=true 76 77# Server must not enforce its own blocklist (for parental control, ads blocking...) 78require_nofilter=true 79 80# Server names to avoid even if they match all criteria 81disabled_server_names=[] 82 83 84## Always use TCP to connect to upstream servers. 85## This can be useful if you need to route everything through Tor. 86## Otherwise, leave this to `false`, as it doesn't improve security 87## (dnscrypt-proxy will always encrypt everything even using UDP), and can 88## only increase latency. 89 90force_tcp=true 91 92 93## SOCKS proxy 94## Uncomment the following line to route all TCP connections to a local Tor node 95## Tor doesn't support UDP, so set `force_tcp` to `true` as well. 96 97# proxy = 'socks5://127.0.0.1:9050' 98 99100## HTTP/HTTPS proxy101## Only for DoH servers102103# http_proxy = 'http://127.0.0.1:8888'104105106## How long a DNS query will wait for a response, in milliseconds.107## If you have a network with *a lot* of latency, you may need to108## increase this. Startup may be slower if you do so.109## Don't increase it too much. 10000 is the highest reasonable value.110111timeout=25000112113114## Keepalive for HTTP (HTTPS, HTTP/2) queries, in seconds115116keepalive=30117118119## Response for blocked queries. Options are `refused`, `hinfo` (default) or120## an IP response. To give an IP response, use the format `a:<IPv4>,aaaa:<IPv6>`.121## Using the `hinfo` option means that some responses will be lies.122## Unfortunately, the `hinfo` option appears to be required for Android 8+123124blocked_query_response='refused'125126127## Load-balancing strategy: 'p2' (default), 'ph', 'first' or 'random'128129# lb_strategy = 'p2'130131## Set to `true` to constantly try to estimate the latency of all the resolvers132## and adjust the load-balancing parameters accordingly, or to `false` to disable.133134# lb_estimator = true135136137## Log level (0-6, default: 2 - 0 is very verbose, 6 only contains fatal errors)138139# log_level = 2140141142## Log file for the application, as an alternative to sending logs to143## the standard system logging service (syslog/Windows event log).144##145## This file is different from other log files, and will not be146## automatically rotated by the application.147148# log_file = '/var/log/dnscrypt-proxy/dnscrypt-proxy.log'149150151## When using a log file, only keep logs from the most recent launch.152153# log_file_latest = true154155156## Use the system logger (syslog on Unix, Event Log on Windows)157158# use_syslog = true159160161## Delay, in minutes, after which certificates are reloaded162163cert_refresh_delay=240164165166## DNSCrypt: Create a new, unique key for every single DNS query167## This may improve privacy but can also have a significant impact on CPU usage168## Only enable if you don't have a lot of network load169170# dnscrypt_ephemeral_keys = false171172173## DoH: Disable TLS session tickets - increases privacy but also latency174175tls_disable_session_tickets=true176177178## DoH: Use a specific cipher suite instead of the server preference179## 49199 = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256180## 49195 = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256181## 52392 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305182## 52393 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305183## 4865 = TLS_AES_128_GCM_SHA256184## 4867 = TLS_CHACHA20_POLY1305_SHA256185##186## On non-Intel CPUs such as MIPS routers and ARM systems (Android, Raspberry Pi...),187## the following suite improves performance.188## This may also help on Intel CPUs running 32-bit operating systems.189##190## Keep tls_cipher_suite empty if you have issues fetching sources or191## connecting to some DoH servers. Google and Cloudflare are fine with it.192193# tls_cipher_suite = [52392, 49199]194195196## Fallback resolvers197## These are normal, non-encrypted DNS resolvers, that will be only used198## for one-shot queries when retrieving the initial resolvers list, and199## only if the system DNS configuration doesn't work.200## No user application queries will ever be leaked through these resolvers,201## and they will not be used after IP addresses of resolvers URLs have been found.202## They will never be used if lists have already been cached, and if stamps203## don't include host names without IP addresses.204## They will not be used if the configured system DNS works.205## Resolvers supporting DNSSEC are recommended.206##207## People in China may need to use 114.114.114.114:53 here.208## Other popular options include 8.8.8.8 and 1.1.1.1.209##210## If more than one resolver is specified, they will be tried in sequence.211212fallback_resolver='0.0.0.0:53'213#fallback_resolvers = ['9.9.9.9:53', '8.8.8.8:53']214215216## Always use the fallback resolver before the system DNS settings.217218ignore_system_dns=true219220221## Maximum time (in seconds) to wait for network connectivity before222## initializing the proxy.223## Useful if the proxy is automatically started at boot, and network224## connectivity is not guaranteed to be immediately available.225## Use 0 to not test for connectivity at all (not recommended),226## and -1 to wait as much as possible.227228netprobe_timeout=0229230## Address and port to try initializing a connection to, just to check231## if the network is up. It can be any address and any port, even if232## there is nothing answering these on the other side. Just don't use233## a local address, as the goal is to check for Internet connectivity.234## On Windows, a datagram with a single, nul byte will be sent, only235## when the system starts.236## On other operating systems, the connection will be initialized237## but nothing will be sent at all.238239#netprobe_address = '9.9.9.9:53'240241242## Offline mode - Do not use any remote encrypted servers.243## The proxy will remain fully functional to respond to queries that244## plugins can handle directly (forwarding, cloaking, ...)245246# offline_mode = false247248249## Additional data to attach to outgoing queries.250## These strings will be added as TXT records to queries.251## Do not use, except on servers explicitly asking for extra data252## to be present.253## encrypted-dns-server can be configured to use this for access control254## in the [access_control] section255256# query_meta = ["key1:value1", "key2:value2", "token:MySecretToken"]257258259## Automatic log files rotation260261# Maximum log files size in MB - Set to 0 for unlimited.262log_files_max_size=10263264# How long to keep backup files, in days265log_files_max_age=7266267# Maximum log files backups to keep (or 0 to keep all backups)268log_files_max_backups=1269270271272#########################273# Filters #274#########################275276## Note: if you are using dnsmasq, disable the `dnssec` option in dnsmasq if you277## configure dnscrypt-proxy to do any kind of filtering (including the filters278## below and blocklists).279## You can still choose resolvers that do DNSSEC validation.280281282## Immediately respond to IPv6-related queries with an empty response283## This makes things faster when there is no IPv6 connectivity, but can284## also cause reliability issues with some stub resolvers.285286block_ipv6=true287288289## Immediately respond to A and AAAA queries for host names without a domain name290291block_unqualified=true292293294## Immediately respond to queries for local zones instead of leaking them to295## upstream resolvers (always causing errors or timeouts).296297block_undelegated=true298299300## TTL for synthetic responses sent when a request has been blocked (due to301## IPv6 or blocklists).302303reject_ttl=600304305306307##################################################################################308# Route queries for specific domains to a dedicated set of servers #309##################################################################################310311## See the `example-forwarding-rules.txt` file for an example312313# forwarding_rules = '/etc/dnscrypt-proxy/forwarding-rules.txt'314315316317###############################318# Cloaking rules #319###############################320321## Cloaking returns a predefined address for a specific name.322## In addition to acting as a HOSTS file, it can also return the IP address323## of a different name. It will also do CNAME flattening.324##325## See the `example-cloaking-rules.txt` file for an example326327cloaking_rules='dnscrypt.cloaking.txt'328329## TTL used when serving entries in cloaking-rules.txt330331# cloak_ttl = 600332333334###########################335# DNS cache #336###########################337338## Enable a DNS cache to reduce latency and outgoing traffic339340cache=true341342343## Cache size344345cache_size=4096346347348## Minimum TTL for cached entries349350cache_min_ttl=2400351352353## Maximum TTL for cached entries354355cache_max_ttl=86400356357358## Minimum TTL for negatively cached entries359360cache_neg_min_ttl=60361362363## Maximum TTL for negatively cached entries364365cache_neg_max_ttl=600366367368369##################################370# Local DoH server #371##################################372373[local_doh]374375## dnscrypt-proxy can act as a local DoH server. By doing so, web browsers376## requiring a direct connection to a DoH server in order to enable some377## features will enable these, without bypassing your DNS proxy.378379## Addresses that the local DoH server should listen to380381# listen_addresses = ['127.0.0.1:3000']382383384## Path of the DoH URL. This is not a file, but the part after the hostname385## in the URL. By convention, `/dns-query` is frequently chosen.386## For each `listen_address` the complete URL to access the server will be:387## `https://<listen_address><path>` (ex: `https://127.0.0.1/dns-query`)388389# path = "/dns-query"390391392## Certificate file and key - Note that the certificate has to be trusted.393## See the documentation (wiki) for more information.394395# cert_file = "localhost.pem"396# cert_key_file = "localhost.pem"397398399400###############################401# Query logging #402###############################403404## Log client queries to a file405406[query_log]407408## Path to the query log file (absolute, or relative to the same directory as the config file)409## Can be set to /dev/stdout in order to log to the standard output.410411# file = '/var/log/dnscrypt-proxy/query.log'412file='dnscrypt.queries.log'413414## Query log format (currently supported: tsv and ltsv)415416format='tsv'417418419## Do not log these query types, to reduce verbosity. Keep empty to log everything.420421# ignored_qtypes = ['DNSKEY', 'NS']422423424425############################################426# Suspicious queries logging #427############################################428429## Log queries for nonexistent zones430## These queries can reveal the presence of malware, broken/obsolete applications,431## and devices signaling their presence to 3rd parties.432433[nx_log]434435## Path to the query log file (absolute, or relative to the same directory as the config file)436437# file = '/var/log/dnscrypt-proxy/nx.log'438439440## Query log format (currently supported: tsv and ltsv)441442format='tsv'443444445446######################################################447# Pattern-based blocking (blocklists) #448######################################################449450## Blocklists are made of one pattern per line. Example of valid patterns:451##452## example.com453## =example.com454## *sex*455## ads.*456## ads*.example.*457## ads*.example[0-9]*.com458##459## Example blocklist files can be found at https://download.dnscrypt.info/blocklists/460## A script to build blocklists from public feeds can be found in the461## `utils/generate-domains-blocklists` directory of the dnscrypt-proxy source code.462463[blocked_names]464465## Path to the file of blocking rules (absolute, or relative to the same directory as the config file)466467# blocked_names_file = 'blocked-names.txt'468469470## Optional path to a file logging blocked queries471472# log_file = 'blocked-names.log'473474475## Optional log format: tsv or ltsv (default: tsv)476477# log_format = 'tsv'478479480481###########################################################482# Pattern-based IP blocking (IP blocklists) #483###########################################################484485## IP blocklists are made of one pattern per line. Example of valid patterns:486##487## 127.*488## fe80:abcd:*489## 192.168.1.4490491[blocked_ips]492493## Path to the file of blocking rules (absolute, or relative to the same directory as the config file)494495# blocked_ips_file = 'blocked-ips.txt'496497498## Optional path to a file logging blocked queries499500# log_file = 'blocked-ips.log'501502503## Optional log format: tsv or ltsv (default: tsv)504505# log_format = 'tsv'506507508509######################################################510# Pattern-based allow lists (blocklists bypass) #511######################################################512513## Allowlists support the same patterns as blocklists514## If a name matches an allowlist entry, the corresponding session515## will bypass names and IP filters.516##517## Time-based rules are also supported to make some websites only accessible at specific times of the day.518519[allowed_names]520521## Path to the file of allow list rules (absolute, or relative to the same directory as the config file)522523# allowed_names_file = 'allowed-names.txt'524525526## Optional path to a file logging allowed queries527528# log_file = 'allowed-names.log'529530531## Optional log format: tsv or ltsv (default: tsv)532533# log_format = 'tsv'534535536537##########################################538# Time access restrictions #539##########################################540541## One or more weekly schedules can be defined here.542## Patterns in the name-based blocked_names file can optionally be followed with @schedule_name543## to apply the pattern 'schedule_name' only when it matches a time range of that schedule.544##545## For example, the following rule in a blocklist file:546## *.youtube.* @time-to-sleep547## would block access to YouTube during the times defined by the 'time-to-sleep' schedule.548##549## {after='21:00', before= '7:00'} matches 0:00-7:00 and 21:00-0:00550## {after= '9:00', before='18:00'} matches 9:00-18:00551552[schedules]553554# [schedules.'time-to-sleep']555# mon = [{after='21:00', before='7:00'}]556# tue = [{after='21:00', before='7:00'}]557# wed = [{after='21:00', before='7:00'}]558# thu = [{after='21:00', before='7:00'}]559# fri = [{after='23:00', before='7:00'}]560# sat = [{after='23:00', before='7:00'}]561# sun = [{after='21:00', before='7:00'}]562563# [schedules.'work']564# mon = [{after='9:00', before='18:00'}]565# tue = [{after='9:00', before='18:00'}]566# wed = [{after='9:00', before='18:00'}]567# thu = [{after='9:00', before='18:00'}]568# fri = [{after='9:00', before='17:00'}]569570571572#########################573# Servers #574#########################575576## Remote lists of available servers577## Multiple sources can be used simultaneously, but every source578## requires a dedicated cache file.579##580## Refer to the documentation for URLs of public sources.581##582## A prefix can be prepended to server names in order to583## avoid collisions if different sources share the same for584## different servers. In that case, names listed in `server_names`585## must include the prefixes.586##587## If the `urls` property is missing, cache files and valid signatures588## must already be present. This doesn't prevent these cache files from589## expiring after `refresh_delay` hours.590591[sources]592593[sources.'public-resolvers']594#url = '/etc/dnscrypt-proxy/public-resolvers.md'595urls=['http://127.0.0.1/dnscrypt-resolvers/public-resolvers.md']596cache_file='public-resolvers.md'597minisign_key='RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'598refresh_delay=72599prefix=''600601## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers602603# [sources.'public-resolvers']604# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md']605# cache_file = '/var/cache/dnscrypt-proxy/public-resolvers.md'606# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'607# prefix = ''608609## Anonymized DNS relays610611# [sources.'relays']612# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/relays.md', 'https://download.dnscrypt.info/resolvers-list/v3/relays.md']613# cache_file = 'relays.md'614# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'615# refresh_delay = 72616# prefix = ''617618## Quad9 over DNSCrypt - https://quad9.net/619620# [sources.quad9-resolvers]621# urls = ['https://www.quad9.net/quad9-resolvers.md']622# minisign_key = 'RWQBphd2+f6eiAqBsvDZEBXBGHQBJfeG6G+wJPPKxCZMoEQYpmoysKUN'623# cache_file = 'quad9-resolvers.md'624# prefix = 'quad9-'625626## Another example source, with resolvers censoring some websites not appropriate for children627## This is a subset of the `public-resolvers` list, so enabling both is useless628629# [sources.'parental-control']630# urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/parental-control.md', 'https://download.dnscrypt.info/resolvers-list/v3/parental-control.md']631# cache_file = '/var/cache/dnscrypt-proxy/parental-control.md'632# minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'633634635636#########################################637# Servers with known bugs #638#########################################639640[broken_implementations]641642# Cisco servers currently cannot handle queries larger than 1472 bytes, and don't643# truncate reponses larger than questions as expected by the DNSCrypt protocol.644# This prevents large responses from being received over UDP and over relays.645#
646# The `dnsdist` server software drops client queries larger than 1500 bytes.647# They are aware of it and are working on a fix.648#
649# The list below enables workarounds to make non-relayed usage more reliable650# until the servers are fixed.651652fragments_blocked=['cisco', 'cisco-ipv6', 'cisco-familyshield', 'cisco-familyshield-ipv6', 'quad9-dnscrypt-ip4-filter-pri', 'quad9-dnscrypt-ip4-nofilter-pri', 'quad9-dnscrypt-ip6-filter-pri', 'quad9-dnscrypt-ip6-nofilter-pri', 'cleanbrowsing-adult', 'cleanbrowsing-family-ipv6', 'cleanbrowsing-family', 'cleanbrowsing-security']653654655656#################################################################657# Certificate-based client authentication for DoH #658#################################################################659660# Use a X509 certificate to authenticate yourself when connecting to DoH servers.661# This is only useful if you are operating your own, private DoH server(s).662# 'creds' maps servers to certificates, and supports multiple entries.663# If you are not using the standard root CA, an optional "root_ca"664# property set to the path to a root CRT file can be added to a server entry.665666[doh_client_x509_auth]667668#
669# creds = [670# { server_name='myserver', client_cert='client.crt', client_key='client.key' }671# ]672673674675################################676# Anonymized DNS #677################################678679[anonymized_dns]680681## Routes are indirect ways to reach DNSCrypt servers.682##683## A route maps a server name ("server_name") to one or more relays that will be684## used to connect to that server.685##686## A relay can be specified as a DNS Stamp (either a relay stamp, or a687## DNSCrypt stamp), an IP:port, a hostname:port, or a server name.688##689## The following example routes "example-server-1" via `anon-example-1` or `anon-example-2`,690## and "example-server-2" via the relay whose relay DNS stamp691## is "sdns://gRIxMzcuNzQuMjIzLjIzNDo0NDM".692##693## !!! THESE ARE JUST EXAMPLES !!!694##695## Review the list of available relays from the "relays.md" file, and, for each696## server you want to use, define the relays you want connections to go through.697##698## Carefully choose relays and servers so that they are run by different entities.699##700## "server_name" can also be set to "*" to define a default route, but this is not701## recommended. If you do so, keep "server_names" short and distinct from relays.702703# routes = [704# { server_name='example-server-1', via=['anon-example-1', 'anon-example-2'] },705# { server_name='example-server-2', via=['sdns://gRIxMzcuNzQuMjIzLjIzNDo0NDM'] }706# ]707708709# Skip resolvers incompatible with anonymization instead of using them directly710711skip_incompatible=false712713714# If public server certificates for a non-conformant server cannot be715# retrieved via a relay, try getting them directly. Actual queries716# will then always go through relays.717718# direct_cert_fallback = false719720721722###############################723# DNS64 #724###############################725726## DNS64 is a mechanism for synthesizing AAAA records from A records.727## It is used with an IPv6/IPv4 translator to enable client-server728## communication between an IPv6-only client and an IPv4-only server,729## without requiring any changes to either the IPv6 or the IPv4 node,730## for the class of applications that work through NATs.731##732## There are two options to synthesize such records:733## Option 1: Using a set of static IPv6 prefixes;734## Option 2: By discovering the IPv6 prefix from DNS64-enabled resolver.735##736## If both options are configured - only static prefixes are used.737## (Ref. RFC6147, RFC6052, RFC7050)738##739## Do not enable unless you know what DNS64 is and why you need it, or else740## you won't be able to connect to anything at all.741742[dns64]743744## (Option 1) Static prefix(es) as Pref64::/n CIDRs.745# prefix = ["64:ff9b::/96"]746747## (Option 2) DNS64-enabled resolver(s) to discover Pref64::/n CIDRs.748## These resolvers are used to query for Well-Known IPv4-only Name (WKN) "ipv4only.arpa." to discover only.749## Set with your ISP's resolvers in case of custom prefixes (other than Well-Known Prefix 64:ff9b::/96).750## IMPORTANT: Default resolvers listed below support Well-Known Prefix 64:ff9b::/96 only.751# resolver = ["[2606:4700:4700::64]:53", "[2001:4860:4860::64]:53"]752753754755########################################756# Static entries #757########################################758759## Optional, local, static list of additional servers760## Mostly useful for testing your own servers.761762[static]763764# [static.'myserver']765# stamp = 'sdns://AQcAAAAAAAAAAAAQMi5kbnNjcnlwdC1jZXJ0Lg'
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)
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.
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.
DNS query log = DNS queries made by Android applications and DNSCrypt-Proxy process.
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).
1#!/system/bin/sh
2 3IPTABLES=/system/bin/iptables
4 5ip link set rmnet0 down
6 7######################################## 8# Prepare DNS environment 910for protocol in tcp udp;do1112# Enforce use of a local DNS server listening to unprivileged port 553313#----------14$IPTABLES -t nat -A OUTPUT ! -o rndis+ -p $protocol --dport 53 -j DNAT --to 127.0.0.1:5533
1516$IPTABLES -t nat -A POSTROUTING ! -o rndis+ -p $protocol --sport 5533 -m conntrack --ctstate ESTABLISHED,RELATED -j SNAT --to-source 127.0.0.1:53
1718# Drop outbound WAN DNS queries19#----------20$IPTABLES -t filter -A OUTPUT -o rmnet+ -p $protocol --dport 53 -j DROP
2122done2324# Drop outbound HTTP traffic25#$IPTABLES -t filter -A OUTPUT -o rmnet+ -p tcp --dport 80 -j DROP26#$IPTABLES -t filter -A FORWARD -o rmnet+ -p tcp --dport 80 -j DROP2728ip link set rmnet0 up
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
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.
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.
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.
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.
Fjordtek is a technology site concerning various topics such as computer networks, cloud solutions, virtualization & container technologies and security practices on critical environments.