ข้ามไปยังเนื้อหาหลัก

DNS traffic can leak outside the VPN tunnel on Android

Privacy App 

We were recently made aware of multiple potential DNS leaks on Android. They stem from bugs in Android itself, and only affect certain apps.

On Monday 22 of April we became aware of a user report on Reddit of a DNS leak. The report detailed how the user managed to leak DNS queries when disabling and enabling VPN while having “Block connections without VPN” on. We immediately started an internal investigation that could confirm the issue. The investigation also led to more findings of scenarios that can cause DNS leaks on Android.

Findings

Identified scenarios where the Android OS can leak DNS traffic:

  • If a VPN is active without any DNS server configured.
  • For a short period of time while a VPN app is re-configuring the tunnel or is being force stopped/crashes.

The leaks seem to be limited to direct calls to the C function getaddrinfo. Apps that use this way to resolve domain names cause leaks in the scenarios listed above. We have not found any leaks from apps that only use Android API:s such as DnsResolver. The Chrome browser is an example of an app that can use getaddrinfo directly.

The above applies regardless of whether Always-on VPN and Block connections without VPN is enabled or not, which is not expected OS behavior and should therefore be fixed upstream in the OS.

We’ve been able to confirm that these leaks occur in multiple versions of Android, including the latest version (Android 14).

Improvements

Our app currently does not set any DNS server in its blocking state. When our app fails to set up a tunnel in a way that is not recoverable, it enters the blocking state. In this state it stops traffic from leaving the device. However, it does not set any DNS server in this state, and as a result the above described DNS leaks can happen. We will work around the OS bug by setting a bogus DNS server for now. You can expect a release with this fix soon.

The leak during tunnel reconnects is harder for us to mitigate in our app. We are still looking for solutions. We can potentially minimize the amount of times a tunnel re-configuration happens, but we currently don’t think this leak can be fully prevented.

It should be made clear that these workarounds should not be needed in any VPN app. Nor is it wrong for an app to use getaddrinfo to resolve domain names. Instead, these issues should be addressed in the OS in order to protect all Android users regardless of which apps they use.

We have reported the issues and suggested improvements to Google and hope that they will address this quickly.

Steps to reproduce

The following steps reproduce the second scenario above, where a VPN user changes the tunnel configuration, e.g. switching to another server or changing DNS server.

Here we use the WireGuard app since it has become a reference Android VPN implementation. It should be noted that the leaks can probably be reproduced with any other Android VPN app also. We use Chrome to trigger the leaks since it is one of the apps we have confirmed uses getaddrinfo.

  1. Download spam_get_requests.html
  2. Install the WireGuard app & Chrome
  3. Import wg1.conf, wg2.conf into WireGuard
  4. Enable the wg1 tunnel in the WireGuard app and allow the VPN permission
  5. In Android VPN Settings enable “Always-on VPN” & “Block connections without VPN” for WireGuard
  6. Start capturing data on your router by using e.g tcpdump
    $ tcpdump -i <INTERFACE> host <IP of android device>
  7. Split the screen to show both WireGuard & Chrome side by side
  8. Open spam_get_requests.html with Chrome & press “Start”
  9. Toggle back and fourth between wg1 and wg2 in the WireGuard app until you see the leaks in the next step.
  10. Observe DNS traffic similar to this on the router:
    11:50:27.816359 IP Pixel-Tablet.lan.53353 > OpenWrt.lan.53: 11200+ A? 307lf5rgn6-19282-11-50-27-519z.mullvad.test.lan. (65)
    11:50:27.816359 IP Pixel-Tablet.lan.48267 > OpenWrt.lan.53: 44347+ A? 307lf5rgn6-19284-11-50-27-579z.mullvad.test.lan. (65)
    11:50:27.816396 IP Pixel-Tablet.lan.16747 > OpenWrt.lan.53: 44584+ A? 307lf5rgn6-19289-11-50-27-729z.mullvad.test. (61)
    11:50:27.816458 IP OpenWrt.lan.53 > Pixel-Tablet.lan.53353: 11200 NXDomain 0/0/0 (65)
    11:50:27.816476 IP Pixel-Tablet.lan.45727 > OpenWrt.lan.53: 40503+ A? 307lf5rgn6-19290-11-50-27-759z.mullvad.test. (61)
    11:50:27.816542 IP OpenWrt.lan.53 > Pixel-Tablet.lan.48267: 44347 NXDomain 0/0/0 (65)
    11:50:27.816588 IP Pixel-Tablet.lan.43821 > OpenWrt.lan.53: 36295+ A? 307lf5rgn6-19291-11-50-27-789z.mullvad.test. (61) 11:50:27.816625 IP OpenWrt.lan.53 > Pixel-Tablet.lan.16747: 44584 NXDomain 0/0/0 (61)

Since “Block connections without VPN” was active, nothing except encrypted WireGuard traffic should have left the device, but here we see plaintext DNS leaving the device.

Conclusions and recommendations

DNS leaks may have serious privacy implications for users, and can be used to derive users' approximate location or find out what websites and services a user uses.

These finding also shows once again that “Block connections without VPN” does not live up to its name (or documentation) and that it has multiple flaws. Apps may still leak DNS traffic during the conditions mentioned above, and as previously reported it still leaks connection check traffic.

Depending on your threat model this might mean that you should avoid using Android altogether for anything sensitive, or employ other mitigations to prevent the leaks. We aim to partially mitigate these problems in our app, so make sure to keep the app up-to-date.