Add a throw route to the VPN endpoint.

Without this, legacy VPN types that don't send all traffic
through a tun or ppp interface, but instead have the kernel
apply IPsec transforms directly to the original packets, will
try to send traffic to the VPN endpoint through the VPN, which
will not work.

Bug: 17462989
Change-Id: I3ebf0cec726dd12b2c57ba5d66775f8c02b25b70
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index afc2a39..4100ae9 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.BIND_VPN_SERVICE;
 import static android.os.UserHandle.PER_USER_RANGE;
+import static android.net.RouteInfo.RTN_THROW;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 
@@ -38,6 +39,7 @@
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
+import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.LocalSocket;
@@ -1220,7 +1222,7 @@
 
                 // Now we are connected. Read and parse the new state.
                 String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
-                if (parameters.length != 6) {
+                if (parameters.length != 7) {
                     throw new IllegalStateException("Cannot parse the state");
                 }
 
@@ -1249,6 +1251,23 @@
                     }
                 }
 
+                // Add a throw route for the VPN server endpoint, if one was specified.
+                String endpoint = parameters[5];
+                if (!endpoint.isEmpty()) {
+                    try {
+                        InetAddress addr = InetAddress.parseNumericAddress(endpoint);
+                        if (addr instanceof Inet4Address) {
+                            mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW));
+                        } else if (addr instanceof Inet6Address) {
+                            mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW));
+                        } else {
+                            Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint);
+                        }
+                    } catch (IllegalArgumentException e) {
+                        Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e);
+                    }
+                }
+
                 // Here is the last step and it must be done synchronously.
                 synchronized (Vpn.this) {
                     // Set the start time