From 4b0f8e6fb707e19799011c1f4a5e4f54603e34b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Sep 2014 01:49:05 +0900 Subject: [PATCH 1/2] Support non-unicast route types: unreachable and throw. Bug: 17462989 Change-Id: I8635472ca3e96ec2866af2de48e6260ab2da13fb --- core/java/android/net/IpPrefix.java | 2 +- core/java/android/net/LinkProperties.java | 3 +- core/java/android/net/RouteInfo.java | 93 +++++++++++++++++-- .../server/NetworkManagementService.java | 22 ++++- 4 files changed, 106 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index f1fa3eb748263..b268986775d70 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -172,7 +172,7 @@ public final class IpPrefix implements Parcelable { /** * Returns a string representation of this {@code IpPrefix}. * - * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::"}. + * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. */ public String toString() { try { diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 3d6a132904114..662c57627f59c 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -381,7 +381,8 @@ public final class LinkProperties implements Parcelable { return new RouteInfo( route.getDestination(), route.getGateway(), - mIfaceName); + mIfaceName, + route.getType()); } /** diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index a4ec80c9a511a..cfd20a047e1e1 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -62,6 +62,23 @@ public final class RouteInfo implements Parcelable { */ private final String mInterface; + + /** Unicast route. @hide */ + public static final int RTN_UNICAST = 1; + + /** Unreachable route. @hide */ + public static final int RTN_UNREACHABLE = 7; + + /** Throw route. @hide */ + public static final int RTN_THROW = 9; + + /** + * The type of this route; one of the RTN_xxx constants above. + */ + private final int mType; + + // Derived data members. + // TODO: remove these. private final boolean mIsHost; private final boolean mHasGateway; @@ -82,7 +99,26 @@ public final class RouteInfo implements Parcelable { * * @hide */ - public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { + public RouteInfo(IpPrefix destination, InetAddress gateway, String iface, int type) { + switch (type) { + case RTN_UNICAST: + case RTN_UNREACHABLE: + case RTN_THROW: + // TODO: It would be nice to ensure that route types that don't have nexthops or + // interfaces, such as unreachable or throw, can't be created if an interface or + // a gateway is specified. This is a bit too complicated to do at the moment + // because: + // + // - LinkProperties sets the interface on routes added to it, and modifies the + // interfaces of all the routes when its interface name changes. + // - Even when the gateway is null, we store a non-null gateway here. + // + // For now, we just rely on the code that sets routes to do things properly. + break; + default: + throw new IllegalArgumentException("Unknown route type " + type); + } + if (destination == null) { if (gateway != null) { if (gateway instanceof Inet4Address) { @@ -117,9 +153,17 @@ public final class RouteInfo implements Parcelable { mDestination = destination; // IpPrefix objects are immutable. mGateway = gateway; // InetAddress objects are immutable. mInterface = iface; // Strings are immutable. + mType = type; mIsHost = isHost(); } + /** + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { + this(destination, gateway, iface, RTN_UNICAST); + } + /** * @hide */ @@ -150,6 +194,8 @@ public final class RouteInfo implements Parcelable { /** * @hide + * + * TODO: Remove this. */ public RouteInfo(LinkAddress destination, InetAddress gateway) { this(destination, gateway, null); @@ -185,6 +231,13 @@ public final class RouteInfo implements Parcelable { this(destination, null, null); } + /** + * @hide + */ + public RouteInfo(IpPrefix destination, int type) { + this(destination, null, null, type); + } + /** * @hide */ @@ -248,13 +301,24 @@ public final class RouteInfo implements Parcelable { return mInterface; } + /** + * Retrieves the type of this route. + * + * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class. + * + * @hide + */ + public int getType() { + return mType; + } + /** * Indicates if this route is a default route (ie, has no destination specified). * * @return {@code true} if the destination has a prefix length of 0. */ public boolean isDefaultRoute() { - return mDestination.getPrefixLength() == 0; + return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0; } /** @@ -345,9 +409,18 @@ public final class RouteInfo implements Parcelable { public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); - val += " ->"; - if (mGateway != null) val += " " + mGateway.getHostAddress(); - if (mInterface != null) val += " " + mInterface; + if (mType == RTN_UNREACHABLE) { + val += " unreachable"; + } else if (mType == RTN_THROW) { + val += " throw"; + } else { + val += " ->"; + if (mGateway != null) val += " " + mGateway.getHostAddress(); + if (mInterface != null) val += " " + mInterface; + if (mType != RTN_UNICAST) { + val += " unknown type " + mType; + } + } return val; } @@ -364,7 +437,8 @@ public final class RouteInfo implements Parcelable { return Objects.equals(mDestination, target.getDestination()) && Objects.equals(mGateway, target.getGateway()) && - Objects.equals(mInterface, target.getInterface()); + Objects.equals(mInterface, target.getInterface()) && + mType == target.getType(); } /** @@ -373,7 +447,8 @@ public final class RouteInfo implements Parcelable { public int hashCode() { return (mDestination.hashCode() * 41) + (mGateway == null ? 0 :mGateway.hashCode() * 47) - + (mInterface == null ? 0 :mInterface.hashCode() * 67); + + (mInterface == null ? 0 :mInterface.hashCode() * 67) + + (mType * 71); } /** @@ -391,6 +466,7 @@ public final class RouteInfo implements Parcelable { byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress(); dest.writeByteArray(gatewayBytes); dest.writeString(mInterface); + dest.writeInt(mType); } /** @@ -408,8 +484,9 @@ public final class RouteInfo implements Parcelable { } catch (UnknownHostException e) {} String iface = in.readString(); + int type = in.readInt(); - return new RouteInfo(dest, gateway, iface); + return new RouteInfo(dest, gateway, iface, type); } public RouteInfo[] newArray(int size) { diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 1318f66f36932..6144078cf552f 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -25,6 +25,9 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_TETHERING; +import static android.net.RouteInfo.RTN_THROW; +import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult; @@ -955,11 +958,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub final Command cmd = new Command("network", "route", action, netId); // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr - final LinkAddress la = route.getDestinationLinkAddress(); cmd.appendArg(route.getInterface()); - cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength()); - if (route.hasGateway()) { - cmd.appendArg(route.getGateway().getHostAddress()); + cmd.appendArg(route.getDestination().toString()); + + switch (route.getType()) { + case RouteInfo.RTN_UNICAST: + if (route.hasGateway()) { + cmd.appendArg(route.getGateway().getHostAddress()); + } + break; + case RouteInfo.RTN_UNREACHABLE: + cmd.appendArg("unreachable"); + break; + case RouteInfo.RTN_THROW: + cmd.appendArg("throw"); + break; } try { @@ -2129,6 +2142,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub modifyAddressFamily("remove", family, netId, iface); } + // TODO: get rid of this and add RTN_UNREACHABLE routes instead. private void modifyAddressFamily(String action, int family, int netId, String iface) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); From 5026279ce45ae78126046607a2634dc9dae93199 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Sep 2014 01:53:35 +0900 Subject: [PATCH 2/2] 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 --- .../com/android/server/connectivity/Vpn.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index afc2a39742620..4100ae91eabfb 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 @@ package com.android.server.connectivity; 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.content.pm.UserInfo; 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 @@ public class Vpn { // 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 @@ public class Vpn { } } + // 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