Here is my experience with 'dnscrypt-proxy' on Android (I use Replicant. Replicant has root and init.d support "out of the box".
To start off, I have spent more than a week digging the web for information on how to do it. I have read many many discussions, questions and answers (including issues here). The official documentation didn't really help. In the very beginning it says:
If you want to change the DNSCrypt resolver, unzip the downloaded archive, edit the RESOLVER_NAME variable in system/etc/init.d/99dnscrypt. Keep the content as a ZIP file, with the original structure.
I have downloaded and unzipped every single release since 2.0.6 (the first one introducing Android binaries). There is no 99dnscrypt in any of them. Neither there is such file in the source code in git. So, my next step was to search the web, read issues here and there, a lot of time and effort.
What I found:
- @quindecim's repo - it seems made for some software called Magisk. I don't want to install additional software which I don't need, give it permissions etc. I just want dnscrypt-proxy.
- There are some solutions for creating a boot service using init.rc. This process seems to involve unpacking the boot image, editing init.rc, and repacking it. This is new to someone like me. I found several softwares/versions which unpack and repack but when testing unpacking and repacking with no modification whatsoever the repacked image is always quite smaller than the original. I decided not to risk bricking my phone, so I stopped exploring this route.
- Researching further, I found this issue and from it - @uzen's repo. Unfortunately, it seems to include a binary with unknown source code in
src/META-INF/com/google/android
, so I won't run it. Instead of putting that blindly on my phone, I looked into the 99dnscrypt it includes and the two sub-scripts it calls. My impression: the author has spent quite some time on that. Shellcheck complains about so many problems though. Regardless of that, I decided to give these 3 scripts a try but unfortunately the result wasn't satisfactory. I couldn't get things to work as expected, so after many hours of digging into that obviusly old shell script code, I decided to return to simplicity and start from scratch.
- Then I found this. The init.d script used by the questioner is pretty much the same one which I tried myself initially. The difference is that I don't get the errors he gets - there are no such selinux messages in my logcat.
The official documentation also suggests installing one of "four (paid) apps" to switch currently running DNS settings to DNSCrypt. That is another thing I don't want to do. Installing additional (especially non-free) software for the sake of improving security through a software like dnscrypt-proxy, thus increasing attack surface and so on, is a logical contradiction.
So, in my search for a simple, clean, and working FOSS solution I used the same steps as in the Stackexchange question. In my dnscrypt-proxy.toml
I enable blocked_names
and put only one line in it for testing:
*.fsf.org
My findings:
I notice that 'dnscrypt-proxy' is started twice on boot:
$ adb shell logcat | grep dns
12-29 19:25:23.100 1993 1993 I sysinit : Running /system/etc/init.d/99dnscrypt
12-29 19:25:23.290 2006 2006 I dnscrypt: Starting dnscrypt-proxy...
12-29 19:25:23.315 2010 2010 I dnscrypt: Changing dns with iptables...
12-29 19:27:38.500 3459 3459 I sysinit : Running /system/etc/init.d/99dnscrypt
12-29 19:27:38.550 3464 3464 I dnscrypt: Starting dnscrypt-proxy...
12-29 19:27:38.595 3467 3467 I dnscrypt: Changing dns with iptables...
$ adb shell ps | grep dns
root 2009 1 813640 6500 futex_wait 40103db0 S dnscrypt-proxy
root 3466 1 808256 7628 futex_wait 4016fdb0 S dnscrypt-proxy
The 'iptables' rules are not applied:
root@i9300:/ # iptables -L | grep 53
1|root@i9300:/ # iptables -t nat -L | grep 53
1|root@i9300:/ #
I kill 'dnscrypt-proxy' manually:
$ adb shell
root@i9300:/ # killall dnscrypt-proxy
root@i9300:/ # killall dnscrypt-proxy
killall: dnscrypt-proxy: No such process
Then I start the service manually (cellular data is not enabled):
root@i9300:/ # /etc/init.d/99dnscrypt
root@i9300:/ # [2022-12-29 19:36:20] [NOTICE] dnscrypt-proxy 2.1.2
[2022-12-29 19:36:20] [NOTICE] Network not available yet -- waiting...
Now, 'logcat' and 'ps' show there is only one runnig process:
12-29 19:36:19.860 5209 5209 I dnscrypt: Starting dnscrypt-proxy...
12-29 19:36:19.970 5213 5213 I dnscrypt: Changing dns with iptables...
$ adb shell ps | grep dns
root 5212 1 812096 7604 futex_wait 401c4db0 S dnscrypt-proxy
The firewall rule is applied correctly too:
root@i9300:/ # iptables -t nat -L | grep 53
DNAT udp -- anywhere anywhere udp dpt:domain to:127.0.0.1:53
Enable cellular data and watch what is happening in 'adb shell':
root@i9300:/ # [2022-12-29 20:08:31] [NOTICE] Network connectivity detected
[2022-12-29 20:08:31] [NOTICE] Now listening to 127.0.0.1:53 [UDP]
[2022-12-29 20:08:31] [NOTICE] Now listening to 127.0.0.1:53 [TCP]
...
// many other regular notices
...
[2022-12-29 20:09:45] [NOTICE] dnscrypt-proxy is ready - live servers: 32
Everything seems to work. Testing to confirm:
root@i9300:/ # host fsf.org
host: Host not found.
1|root@i9300:/ # host gnu.org
gnu.org has address 209.51.188.116
So, the blocked_names section works and resolving works.
Next, I disabled cellular data, unplugged the USB cable connected to the computer and connected the external WiFi adapter (Replicant needs an external RYF adapter as the phone's built in one won't work without proprietary software). So, I could not test with ADB any more but only using the limited "Terminal" application in Replicant and using the browser that comes with Replicant (no idea what its name is).
In that terminal (rewriting manually here):
host -v fsf.org
host: Host not found.
host -v gnu.org
host: Host not found.
and so on - it seem nothing resolved.
In the browser I see a different result though:
- fsf.org works (although it must not resolve)
- gnu.org works
- other sites work
Obviously, things don't work as expected when using WiFi.
Connecting the phone to the computer again I see that 'dnscrypt-proxy' process is still active. Re-testing with cellular data again shows the same result as above: fsf.org is not resolved, other domains are.
The questions are:
-
Why only the logging commands of the init.d script work, considering that the script is ran by root at boot time?
-
Why (even with manual starting of the service) the behavior is different when using WiFi?
-
How to make this service work on boot with all connections (cellular, WiFi, reverse USB tethering, etc) without requiring manual starting through ADB or additional apps (assuming one already has root and init.d support)?
It would be really great if someone can update the documentation.
Best wishes for the new year!