1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import android.annotation.IntRange; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.annotation.TestApi; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.util.Pair; 26 27 import java.net.Inet4Address; 28 import java.net.Inet6Address; 29 import java.net.InetAddress; 30 import java.net.UnknownHostException; 31 import java.util.Arrays; 32 import java.util.Comparator; 33 34 /** 35 * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a 36 * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of 37 * information: 38 * 39 * <ul> 40 * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. 41 * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits 42 * in the IP address, starting from the most significant bit in network byte order, that 43 * are constant for all addresses in the prefix. 44 * </ul> 45 * 46 * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from 47 * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix 48 * <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to 49 * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive. 50 * 51 * Objects of this class are immutable. 52 */ 53 public final class IpPrefix implements Parcelable { 54 private final byte[] address; // network byte order 55 private final int prefixLength; 56 checkAndMaskAddressAndPrefixLength()57 private void checkAndMaskAddressAndPrefixLength() { 58 if (address.length != 4 && address.length != 16) { 59 throw new IllegalArgumentException( 60 "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); 61 } 62 NetworkUtils.maskRawAddress(address, prefixLength); 63 } 64 65 /** 66 * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in 67 * network byte order and a prefix length. Silently truncates the address to the prefix length, 68 * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}. 69 * 70 * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. 71 * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 72 * 73 * @hide 74 */ IpPrefix(@onNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength)75 public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) { 76 this.address = address.clone(); 77 this.prefixLength = prefixLength; 78 checkAndMaskAddressAndPrefixLength(); 79 } 80 81 /** 82 * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently 83 * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently 84 * converted to {@code 192.0.2.0/24}. 85 * 86 * @param address the IP address. Must be non-null. 87 * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 88 * @hide 89 */ 90 @SystemApi 91 @TestApi IpPrefix(@onNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength)92 public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) { 93 // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, 94 // which is unnecessary because getAddress() already returns a clone. 95 this.address = address.getAddress(); 96 this.prefixLength = prefixLength; 97 checkAndMaskAddressAndPrefixLength(); 98 } 99 100 /** 101 * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". 102 * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} 103 * is silently converted to {@code 192.0.2.0/24}. 104 * 105 * @param prefix the prefix to parse 106 * 107 * @hide 108 */ 109 @SystemApi 110 @TestApi IpPrefix(@onNull String prefix)111 public IpPrefix(@NonNull String prefix) { 112 // We don't reuse the (InetAddress, int) constructor because "error: call to this must be 113 // first statement in constructor". We could factor out setting the member variables to an 114 // init() method, but if we did, then we'd have to make the members non-final, or "error: 115 // cannot assign a value to final variable address". So we just duplicate the code here. 116 Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix); 117 this.address = ipAndMask.first.getAddress(); 118 this.prefixLength = ipAndMask.second; 119 checkAndMaskAddressAndPrefixLength(); 120 } 121 122 /** 123 * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two 124 * objects are equal if they have the same startAddress and prefixLength. 125 * 126 * @param obj the object to be tested for equality. 127 * @return {@code true} if both objects are equal, {@code false} otherwise. 128 */ 129 @Override equals(Object obj)130 public boolean equals(Object obj) { 131 if (!(obj instanceof IpPrefix)) { 132 return false; 133 } 134 IpPrefix that = (IpPrefix) obj; 135 return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; 136 } 137 138 /** 139 * Gets the hashcode of the represented IP prefix. 140 * 141 * @return the appropriate hashcode value. 142 */ 143 @Override hashCode()144 public int hashCode() { 145 return Arrays.hashCode(address) + 11 * prefixLength; 146 } 147 148 /** 149 * Returns a copy of the first IP address in the prefix. Modifying the returned object does not 150 * change this object's contents. 151 * 152 * @return the address in the form of a byte array. 153 */ getAddress()154 public @NonNull InetAddress getAddress() { 155 try { 156 return InetAddress.getByAddress(address); 157 } catch (UnknownHostException e) { 158 // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte 159 // array is the wrong length, but we check that in the constructor. 160 throw new IllegalArgumentException("Address is invalid"); 161 } 162 } 163 164 /** 165 * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth 166 * element). Modifying the returned array does not change this object's contents. 167 * 168 * @return the address in the form of a byte array. 169 */ getRawAddress()170 public @NonNull byte[] getRawAddress() { 171 return address.clone(); 172 } 173 174 /** 175 * Returns the prefix length of this {@code IpPrefix}. 176 * 177 * @return the prefix length. 178 */ 179 @IntRange(from = 0, to = 128) getPrefixLength()180 public int getPrefixLength() { 181 return prefixLength; 182 } 183 184 /** 185 * Determines whether the prefix contains the specified address. 186 * 187 * @param address An {@link InetAddress} to test. 188 * @return {@code true} if the prefix covers the given address. {@code false} otherwise. 189 */ contains(@onNull InetAddress address)190 public boolean contains(@NonNull InetAddress address) { 191 byte[] addrBytes = address.getAddress(); 192 if (addrBytes == null || addrBytes.length != this.address.length) { 193 return false; 194 } 195 NetworkUtils.maskRawAddress(addrBytes, prefixLength); 196 return Arrays.equals(this.address, addrBytes); 197 } 198 199 /** 200 * Returns whether the specified prefix is entirely contained in this prefix. 201 * 202 * Note this is mathematical inclusion, so a prefix is always contained within itself. 203 * @param otherPrefix the prefix to test 204 * @hide 205 */ containsPrefix(@onNull IpPrefix otherPrefix)206 public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { 207 if (otherPrefix.getPrefixLength() < prefixLength) return false; 208 final byte[] otherAddress = otherPrefix.getRawAddress(); 209 NetworkUtils.maskRawAddress(otherAddress, prefixLength); 210 return Arrays.equals(otherAddress, address); 211 } 212 213 /** 214 * @hide 215 */ isIPv6()216 public boolean isIPv6() { 217 return getAddress() instanceof Inet6Address; 218 } 219 220 /** 221 * @hide 222 */ isIPv4()223 public boolean isIPv4() { 224 return getAddress() instanceof Inet4Address; 225 } 226 227 /** 228 * Returns a string representation of this {@code IpPrefix}. 229 * 230 * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. 231 */ toString()232 public String toString() { 233 try { 234 return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength; 235 } catch(UnknownHostException e) { 236 // Cosmic rays? 237 throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e); 238 } 239 } 240 241 /** 242 * Implement the Parcelable interface. 243 */ describeContents()244 public int describeContents() { 245 return 0; 246 } 247 248 /** 249 * Implement the Parcelable interface. 250 */ writeToParcel(Parcel dest, int flags)251 public void writeToParcel(Parcel dest, int flags) { 252 dest.writeByteArray(address); 253 dest.writeInt(prefixLength); 254 } 255 256 /** 257 * Returns a comparator ordering IpPrefixes by length, shorter to longer. 258 * Contents of the address will break ties. 259 * @hide 260 */ lengthComparator()261 public static Comparator<IpPrefix> lengthComparator() { 262 return new Comparator<IpPrefix>() { 263 @Override 264 public int compare(IpPrefix prefix1, IpPrefix prefix2) { 265 if (prefix1.isIPv4()) { 266 if (prefix2.isIPv6()) return -1; 267 } else { 268 if (prefix2.isIPv4()) return 1; 269 } 270 final int p1len = prefix1.getPrefixLength(); 271 final int p2len = prefix2.getPrefixLength(); 272 if (p1len < p2len) return -1; 273 if (p2len < p1len) return 1; 274 final byte[] a1 = prefix1.address; 275 final byte[] a2 = prefix2.address; 276 final int len = a1.length < a2.length ? a1.length : a2.length; 277 for (int i = 0; i < len; ++i) { 278 if (a1[i] < a2[i]) return -1; 279 if (a1[i] > a2[i]) return 1; 280 } 281 if (a2.length < len) return 1; 282 if (a1.length < len) return -1; 283 return 0; 284 } 285 }; 286 } 287 288 /** 289 * Implement the Parcelable interface. 290 */ 291 public static final @android.annotation.NonNull Creator<IpPrefix> CREATOR = 292 new Creator<IpPrefix>() { 293 public IpPrefix createFromParcel(Parcel in) { 294 byte[] address = in.createByteArray(); 295 int prefixLength = in.readInt(); 296 return new IpPrefix(address, prefixLength); 297 } 298 299 public IpPrefix[] newArray(int size) { 300 return new IpPrefix[size]; 301 } 302 }; 303 } 304