Merge changes I3ebf0cec,I8635472c into lmp-dev
* changes:
Add a throw route to the VPN endpoint.
Support non-unicast route types: unreachable and throw.
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index f1fa3eb..b268986 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -172,7 +172,7 @@
/**
* 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 3d6a132..662c576 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -381,7 +381,8 @@
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 a4ec80c..cfd20a0 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -62,6 +62,23 @@
*/
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 @@
*
* @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,10 +153,18 @@
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
*/
public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
@@ -150,6 +194,8 @@
/**
* @hide
+ *
+ * TODO: Remove this.
*/
public RouteInfo(LinkAddress destination, InetAddress gateway) {
this(destination, gateway, null);
@@ -188,6 +234,13 @@
/**
* @hide
*/
+ public RouteInfo(IpPrefix destination, int type) {
+ this(destination, null, null, type);
+ }
+
+ /**
+ * @hide
+ */
public static RouteInfo makeHostRoute(InetAddress host, String iface) {
return makeHostRoute(host, null, iface);
}
@@ -249,12 +302,23 @@
}
/**
+ * 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 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 @@
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 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 @@
byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
dest.writeByteArray(gatewayBytes);
dest.writeString(mInterface);
+ dest.writeInt(mType);
}
/**
@@ -408,8 +484,9 @@
} 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 1318f66..6144078 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_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 @@
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 @@
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);
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