androidroutestun

Android VpnService. Why does all traffic go through the TUN device?


I created a TUN device using VpnService. Why does the TUN interface have the highest priority among other network interfaces of my device?

Update #1

This is how I configured the TUN device:

mInterface = new Builder().setSession(getString(R.string.app_name))
        .addAddress("10.0.1.1", 24)
        .addRoute("0.0.0.0", 1)
        .addRoute("128.0.0.0", 1)
        .establish();

Update #2

This is the output of route -n without the TUN device:

shell@m0:/ $ busybox route -n
busybox route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.197.55.0     0.0.0.0         255.255.255.0   U     0      0        0 rmnet0

This is the output of route -n with the TUN device:

shell@m0:/ $ busybox route -n
busybox route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 tun0
10.197.55.0     0.0.0.0         255.255.255.0   U     0      0        0 rmnet0
shell@m0:/ $

Solution

  • If VpnService is enabled on Android, it does not mean that all traffic goes through VpnTunnel. This depends on IP route and allow/disable application proxy settings.

    mInterface = new Builder().setSession(getString(R.string.app_name))
            .addAddress("10.0.1.1", 24)
            .addRoute("0.0.0.0", 1)
            .addRoute("128.0.0.0", 1)
            .establish();
    

    The above code is obviously global routing, equivalent to 0.0.0.0/0, as you probably know from OpenVPN settings.

    If the default gateway is tun, all IP traffic passes through the tun device.

    In this case, if you don't want a socket traffic to pass through tun, you need to call VpnService::p rotect function for socket-fd to protect fd.

    But that's not enough, you'll also need to find a valid network (not a VPN), call its Network::bindSocket function, and have a Socket go over that network and out.

    If you don't want to protect the socket with the Network::bindSocket function! Then you can set the default network, but it is only valid for the android-process of opening the VPN service.

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                try {
                    ConnectivityManager cm = PppVpnNetworkListener.getConnectivityManager(this._service);
                    if (cm != null) {
                        cm.bindProcessToNetwork(network);
                    }
                } catch (Throwable ignored) {
                }
            }
            try {
                ConnectivityManager.setProcessDefaultNetwork(network);
            } catch (Throwable ignored) {
            }