diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java new file mode 100644 index 0000000000..a14d13f176 --- /dev/null +++ b/core/java/android/net/IpPrefix.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +/** + * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a + * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of + * information: + * + * + * + * For example, the prefix 192.0.2.0/24 covers the 256 IPv4 addresses from + * 192.0.2.0 to 192.0.2.255, inclusive, and the prefix + * 2001:db8:1:2 covers the 2^64 IPv6 addresses from 2001:db8:1:2:: to + * 2001:db8:1:2:ffff:ffff:ffff:ffff, inclusive. + * + * Objects of this class are immutable. + */ +public final class IpPrefix implements Parcelable { + private final byte[] address; // network byte order + private final int prefixLength; + + /** + * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in + * network byte order and a prefix length. + * + * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. + * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * + * @hide + */ + public IpPrefix(byte[] address, int prefixLength) { + if (address.length != 4 && address.length != 16) { + throw new IllegalArgumentException( + "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); + } + if (prefixLength < 0 || prefixLength > (address.length * 8)) { + throw new IllegalArgumentException("IpPrefix with " + address.length + + " bytes has invalid prefix length " + prefixLength); + } + this.address = address.clone(); + this.prefixLength = prefixLength; + // TODO: Validate that the non-prefix bits are zero + } + + /** + * @hide + */ + public IpPrefix(InetAddress address, int prefixLength) { + this(address.getAddress(), prefixLength); + } + + /** + * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two + * objects are equal if they have the same startAddress and prefixLength. + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IpPrefix)) { + return false; + } + IpPrefix that = (IpPrefix) obj; + return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; + } + + /** + * Gets the hashcode of the represented IP prefix. + * + * @return the appropriate hashcode value. + */ + @Override + public int hashCode() { + return Arrays.hashCode(address) + 11 * prefixLength; + } + + /** + * Returns a copy of the first IP address in the prefix. Modifying the returned object does not + * change this object's contents. + * + * @return the address in the form of a byte array. + */ + public InetAddress getAddress() { + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte + // array is the wrong length, but we check that in the constructor. + return null; + } + } + + /** + * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth + * element). Modifying the returned array does not change this object's contents. + * + * @return the address in the form of a byte array. + */ + public byte[] getRawAddress() { + return address.clone(); + } + + /** + * Returns the prefix length of this {@code IpAddress}. + * + * @return the prefix length. + */ + public int getPrefixLength() { + return prefixLength; + } + + /** + * Implement the Parcelable interface. + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(address); + dest.writeInt(prefixLength); + } + + /** + * Implement the Parcelable interface. + */ + public static final Creator CREATOR = + new Creator() { + public IpPrefix createFromParcel(Parcel in) { + byte[] address = in.createByteArray(); + int prefixLength = in.readInt(); + return new IpPrefix(address, prefixLength); + } + + public IpPrefix[] newArray(int size) { + return new IpPrefix[size]; + } + }; +} diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index cff9025d74..8eefa0f55f 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -44,7 +44,7 @@ import java.util.List; * does not affect live networks. * */ -public class LinkProperties implements Parcelable { +public final class LinkProperties implements Parcelable { // The interface described by the network link. private String mIfaceName; private ArrayList mLinkAddresses = new ArrayList(); @@ -77,9 +77,15 @@ public class LinkProperties implements Parcelable { } } + /** + * @hide + */ public LinkProperties() { } + /** + * @hide + */ public LinkProperties(LinkProperties source) { if (source != null) { mIfaceName = source.getInterfaceName(); @@ -267,7 +273,7 @@ public class LinkProperties implements Parcelable { } /** - * Returns all the {@link LinkAddress} for DNS servers on this link. + * Returns all the {@link InetAddress} for DNS servers on this link. * * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on * this link. @@ -457,7 +463,6 @@ public class LinkProperties implements Parcelable { /** * Implement the Parcelable interface - * @hide */ public int describeContents() { return 0; @@ -477,12 +482,12 @@ public class LinkProperties implements Parcelable { String domainName = "Domains: " + mDomains; - String mtu = "MTU: " + mMtu; + String mtu = " MTU: " + mMtu; String routes = " Routes: ["; for (RouteInfo route : mRoutes) routes += route.toString() + ","; routes += "] "; - String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); + String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " "); String stacked = ""; if (mStackedLinks.values().size() > 0) { diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index ad8e4f7eec..6d65d8f069 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -35,10 +35,10 @@ import java.util.Objects; * * A route contains three pieces of information: *
    - *
  • a destination {@link LinkAddress} for directly-connected subnets. If this is - * {@code null} it indicates a default route of the address family (IPv4 or IPv6) + *
  • a destination {@link IpPrefix} specifying the network destinations covered by this route. + * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6) * implied by the gateway IP address. - *
  • a gateway {@link InetAddress} for default routes. If this is {@code null} it + *
  • a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it * indicates a directly-connected route. *
  • an interface (which may be unspecified). *
@@ -46,9 +46,10 @@ import java.util.Objects; * destination and gateway are both specified, they must be of the same address family * (IPv4 or IPv6). */ -public class RouteInfo implements Parcelable { +public final class RouteInfo implements Parcelable { /** * The IP destination address for this route. + * TODO: Make this an IpPrefix. */ private final LinkAddress mDestination; @@ -80,6 +81,19 @@ public class RouteInfo implements Parcelable { * @param destination the destination prefix * @param gateway the IP address to route packets through * @param iface the interface name to send packets on + * + * TODO: Convert to use IpPrefix. + * + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { + this(destination == null ? null : + new LinkAddress(destination.getAddress(), destination.getPrefixLength()), + gateway, iface); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { if (destination == null) { @@ -128,8 +142,17 @@ public class RouteInfo implements Parcelable { *

* Destination and gateway may not both be null. * - * @param destination the destination address and prefix in a {@link LinkAddress} + * @param destination the destination address and prefix in an {@link IpPrefix} * @param gateway the {@link InetAddress} to route packets through + * + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway) { + this(destination, gateway, null); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway) { this(destination, gateway, null); @@ -139,16 +162,27 @@ public class RouteInfo implements Parcelable { * Constructs a default {@code RouteInfo} object. * * @param gateway the {@link InetAddress} to route packets through + * + * @hide */ public RouteInfo(InetAddress gateway) { - this(null, gateway, null); + this((LinkAddress) null, gateway, null); } /** * Constructs a {@code RouteInfo} object representing a direct connected subnet. * - * @param destination the {@link LinkAddress} describing the address and prefix + * @param destination the {@link IpPrefix} describing the address and prefix * length of the subnet. + * + * @hide + */ + public RouteInfo(IpPrefix destination) { + this(destination, null, null); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination) { this(destination, null, null); @@ -194,11 +228,19 @@ public class RouteInfo implements Parcelable { } /** - * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}. + * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. * - * @return {@link LinkAddress} specifying the destination. This is never {@code null}. + * @return {@link IpPrefix} specifying the destination. This is never {@code null}. */ - public LinkAddress getDestination() { + public IpPrefix getDestination() { + return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength()); + } + + /** + * TODO: Convert callers to use IpPrefix and then remove. + * @hide + */ + public LinkAddress getDestinationLinkAddress() { return mDestination; } @@ -233,7 +275,8 @@ public class RouteInfo implements Parcelable { /** * Indicates if this route is a host route (ie, matches only a single host address). * - * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6. + * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6, + * respectively. * @hide */ public boolean isHostRoute() { @@ -295,13 +338,22 @@ public class RouteInfo implements Parcelable { return bestRoute; } + /** + * Returns a human-readable description of this object. + */ public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); - if (mGateway != null) val += " -> " + mGateway.getHostAddress(); + val += " ->"; + if (mGateway != null) val += " " + mGateway.getHostAddress(); + if (mInterface != null) val += " " + mInterface; return val; } + /** + * Compares this RouteInfo object against the specified object and indicates if they are equal. + * @return {@code true} if the objects are equal, {@code false} otherwise. + */ public boolean equals(Object obj) { if (this == obj) return true; @@ -314,6 +366,9 @@ public class RouteInfo implements Parcelable { Objects.equals(mInterface, target.getInterface()); } + /** + * Returns a hashcode for this RouteInfo object. + */ public int hashCode() { return (mDestination == null ? 0 : mDestination.hashCode() * 41) + (mGateway == null ? 0 :mGateway.hashCode() * 47) @@ -323,7 +378,6 @@ public class RouteInfo implements Parcelable { /** * Implement the Parcelable interface - * @hide */ public int describeContents() { return 0; @@ -331,7 +385,6 @@ public class RouteInfo implements Parcelable { /** * Implement the Parcelable interface - * @hide */ public void writeToParcel(Parcel dest, int flags) { if (mDestination == null) { @@ -354,7 +407,6 @@ public class RouteInfo implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public static final Creator CREATOR = new Creator() { diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java index 55d6592d9a..01283a65ba 100644 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ b/core/tests/coretests/src/android/net/RouteInfoTest.java @@ -43,17 +43,17 @@ public class RouteInfoTest extends TestCase { // Invalid input. try { - r = new RouteInfo(null, null, "rmnet0"); + r = new RouteInfo((LinkAddress) null, null, "rmnet0"); fail("Expected RuntimeException: destination and gateway null"); } catch(RuntimeException e) {} // Null destination is default route. - r = new RouteInfo(null, Address("2001:db8::1"), null); + r = new RouteInfo((LinkAddress) null, Address("2001:db8::1"), null); assertEquals(Prefix("::/0"), r.getDestination()); assertEquals(Address("2001:db8::1"), r.getGateway()); assertNull(r.getInterface()); - r = new RouteInfo(null, Address("192.0.2.1"), "wlan0"); + r = new RouteInfo((LinkAddress) null, Address("192.0.2.1"), "wlan0"); assertEquals(Prefix("0.0.0.0/0"), r.getDestination()); assertEquals(Address("192.0.2.1"), r.getGateway()); assertEquals("wlan0", r.getInterface()); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2ece189f8f..671206ff3b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1871,7 +1871,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetd.addRoute(netId, r); } if (exempt) { - LinkAddress dest = r.getDestination(); + LinkAddress dest = r.getDestinationLinkAddress(); if (!mExemptAddresses.contains(dest)) { mNetd.setHostExemption(dest); mExemptAddresses.add(dest); @@ -1904,7 +1904,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { mNetd.removeRoute(netId, r); } - LinkAddress dest = r.getDestination(); + LinkAddress dest = r.getDestinationLinkAddress(); if (mExemptAddresses.contains(dest)) { mNetd.clearHostExemption(dest); mExemptAddresses.remove(dest);