[Networking] willkits:
Adding exception to "Block connections without VPN" (Question & my research so far)

Background

I have a VPN with "Always-on" and "Block connections without VPN" enabled. This prevents connections to the local network. This is what I normally want. However, I would like to be able to communicate with one host on my network (a Chromecast). Currently I have to disable "Block connections without VPN" whenever I want to cast to the Chromecast device. Running Android 9.0, rooted.

Goal

Allow my phone to communicate with 192.168.0.10 even when "Block connections without VPN" is enabled.

Preliminary tests

- I could not ping 192.168.0.10 as a normal user (Permission Denied). However, I could ping it as root.

- There were no changes to the iptables rules when enabling/disabling "Block connections without VPN"

Source Code Research

I dove into the Android source code and these are my discoveries so far:

- Internally "Block connections without VPN" is referred to as "lockdown_vpn" or just "lockdown"

- As expected, "Block connections without VPN" does not use iptables.

- Instead, it uses netd

- The key code is in frameworks/base/services/core/java/com/android/server/connectivity/Vpn.java, setVpnForcedLocked()

- The way the blocking is done is to add a netd blocking rule for every UID except for the VPN UID and UID 0 (root).

- There is also a list of "whitelisted packages" that won't be blocked. This is an empty list initially but can be changed by calling a function.

Utilities research

- netd appears to be an Android-specific centralized networking service

- The command line tool to interface with netd is ndc (not to be confused with ndc used for controlling name servers on other platforms)

- Starting with Android 8.0, "vendor code" is restricted from directly calling many of Android's networking tools, including ndc (see source.android.com/devices/architecture/hidl/network-stack).

- Moreover, ndc has regular expressions that control what command line arguments will be accepted (see netutils_wrappers/NetUtilsWrapper-1.0.cpp). The list of allowed ndc commands is limited to creating/modifying/adding rules to networks with the format "oem[0-9]+".

- There is no documentation for ndc (or netd for that matter). A random posting online that has a full list of ndc's commands (presumably pre-Android 8.0) shows promising commands like "route" and "set_egress_dest_rule". But trying those in Android 9.0's ndc gives "Command not recognized".

Possible solutions

- Compile a version of ndc that doesn't have the restrictions on command line arguments. From what I can surmise, it is only the regular expressions in the netutils wrapper that restrict what ndc can do. I think an ndc binary without those regular expressions would be allowed to make any changes to netd (when run by root).

- Write a Java program that adds netd rules that allow communication with 192.168.0.10.

- Write a Java program that adds "Google Home" or other Chromecast-capable packages as whitelisted packages. This is not ideal since those packages would be able to communicate with any host on the local network (not just 192.168.0.10), but it's one option. Alternatively, maybe there is an interface somewhere that already exists to add whitelisted packages.

- Try to create/modify/add rules to "oem[0-9]+" networks. It seems unlikely any rules added to these would override the lockdown rules (or even be relevant to traffic going out over wlan0), but it's possible.

Any ideas welcome. Otherwise, hopefully my research will help someone in the future.