androidvpnandroid-vpn-service

How to implement VPN split tunneling in Android's VpnService to exclude certain IPs from the VPN tunnel?


I am trying to implement split tunneling in an Android VPN application. Specifically, I want all traffic to go through the VPN by default, but certain IPs should bypass the VPN and use the regular internet connection.

For example, in the Shadowsocks project, their VpnService implementation routes all traffic through the VPN. I need to modify it to exclude specific IPs or websites from the VPN tunnel. Here's the shadowsocks VpnService code, the part I'm guessing should be modified is this: https://github.com/shadowsocks/shadowsocks-android/blob/master/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt

when (profile.route) {
    Acl.ALL, Acl.BYPASS_CHN, Acl.CUSTOM_RULES -> {
        builder.addRoute("0.0.0.0", 0)
        if (profile.ipv6) builder.addRoute("::", 0)
    }
    else -> {
        resources.getStringArray(R.array.bypass_private_route).forEach {
            val subnet = Subnet.fromString(it)!!
            builder.addRoute(subnet.address.hostAddress!!, subnet.prefixSize)
        }
        builder.addRoute(PRIVATE_VLAN4_ROUTER, 32)
        // https://issuetracker.google.com/issues/149636790
        if (profile.ipv6) builder.addRoute("2000::", 3)
    }
}

Solution

  • We managed to implement split tunneling with the following approach:

    For Android 33+, we used builder.excludeRoute to exclude the desired IPs from the VPN. For versions below Android 33, we relied on builder.addRoute and included the required IP addresses calculated using the WireGuard AllowedIPs Calculator.