-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android ConnectivityManager->getLinkProperties->getDnsServers can provide current DNS config #2116
Comments
I know this one, I think you might have to manually grant permissions for writing secure settings if you want to change it however, which you have to do via adb/pm since the Play Store probably won't allow it in the manifest. |
In Android prior to 8 there was an API to ask Android what DNS config it was currently using, by querying system properties net.dns1, net.dns2, etc. That API has been disabled, the net.dns* properties are now empty strings. The ConnectivityManager APIs return correct values in current Android versions, but we'd be reverse engineering what Android does to assemble its DNS config rather than being able to ask Android directly. |
Proof of concept in https://github.com/tailscale/tailscale-android/commits/dns and https://github.com/tailscale/tailscale/commits/android-dns There is something missing: when my phone moved from Wi-Fi to LTE, it kept trying to use the Wi-Fi DNS servers which were no longer reachable. Currently there is no code which reacts to link changes in Android in order to update the DNS servers, something would need to. |
Findings so far:
It is surprisingly difficult to figure out if Android is using Wi-Fi or LTE for connectivity. One way is by running Wi-fi up:
Wi-fi down:
However not all Android devices have an
|
The correct way has changed over time, but there are definitely official ways without resorting to inspecting route tables. https://stackoverflow.com/questions/3841317/how-do-i-see-if-wi-fi-is-connected-on-android has a bunch of ways (some the old deprecated ways) |
There are several good possibilities in that stackoverflow question, I'll make some notes on findings here: NetworkCapabilities.NET_CAPABILITY_INTERNET
with Wifi connected, both rmnet_data1 and wlan0 have NET_CAPABILITY_INTERNET set. Also how to get notified when the Private DNS settings change: |
Using this code:
Pixel3a running Android 12With Wi-Fi on we get:
With Wi-Fi off we get:
The best option I can see is heuristic:
Nexus 7 (2013) running Android 6.0.1:No interfaces returned by getAllNetworks() ? The API is present: the app doesn't crash, and getAllNetworks() was added in API level 21. It just doesn't seem to return any interfaces, even with the Wi-Fi on. This device is Wi-Fi only, no cellular radio. xamarin/Essentials#911 reports roughly the same issue, some devices with Android 6 just don't return anything in However with Android versions prior to 8 we can query the {net.dns1, net.dns2, net.dns3, net.dns4} SystemProperties directly. Access to those properties was removed in Android 8. So I think we can do an implementation of:
Code implementing both of these ideas is in https://github.com/tailscale/tailscale-android/commits/dns It depends on OSS support in https://github.com/tailscale/tailscale/commits/android-dns Update 11/19: |
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Noting this here to ensure we don't lose track of it: Android API level 29 (Android 10) added a DnsResolver.RawQuery which would allow submission of a DNS packet for the OS to handle. Since the Tailscale app is marked as not using the VPN for its own traffic, there is a chance that this will use only the platform, non-VPN DNS resolvers. This could be used to construct a fallback. |
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Add getDnsConfigAsString() to retrieve the current DNS configuration from the Android platform. This implements several mechanisms to retrieve DNS information, suitable for different Android versions: Android 7 and later use ConnectivityManager getAllNetworks(), then iterate over each network to retrieve DNS servers and search domains using the LinkProperties. Android 6 and earlier can only retrieve the currently active interface using ConnectivityManager getActiveNetwork(), but have two additional fallback options which leverage the system properties available in older Android releases. Fixes tailscale/tailscale#2116 Updates tailscale/tailscale#988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Out and about yesterday using a debug build with tailscale/tailscale-android#23, I noticed the phone DNS wasn't working until I turned Tailscale off. getDnsConfigFromLinkProperties had returned an empty list, right after the phone woke up from deep sleep.
What to do about this?
|
Add getDnsConfigAsString() to retrieve the current DNS configuration from the Android platform. This implements several mechanisms to retrieve DNS information, suitable for different Android versions: Android 7 and later use ConnectivityManager getAllNetworks(), then iterate over each network to retrieve DNS servers and search domains using the LinkProperties. Android 6 and earlier can only retrieve the currently active interface using ConnectivityManager getActiveNetwork(), but have two additional fallback options which leverage the system properties available in older Android releases. Fixes tailscale/tailscale#2116 Updates tailscale/tailscale#988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Allow users of CallbackRouter to supply a GetBaseConfig implementation. This is expected to be used on Android, which currently lacks both a) platform support for Split-DNS and b) a way to retrieve the current DNS servers. iOS/macOS also use the CallbackRouter but have platform support for SplitDNS, so don't need getBaseConfig. Updates #2116 Updates #988 Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Noting this for reference later: currently the Android app applies DNS configurations without being able to know the current DNS config. It looks like there is a way to roughly reconstruct the Android DNS config: there is a DNSDig app on Android which does so. From disassembling the APK, it uses ConnectivityManager->getLinkProperties->getDnsServers for each link. It likely chooses the set of DNS servers from the currently active link.
This mechanism isn't perfect, for example in the Settings > Network & internet > Private DNS one can set a DNS-over-TLS server to use. DNSDig doesn't reflect it when a Private DNS server is active, so doesn't appear to have a way to read out the Private DNS setting.
The text was updated successfully, but these errors were encountered: