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.Nullable; 22 import android.annotation.SystemApi; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.util.Pair; 26 27 import com.android.net.module.util.NetUtils; 28 29 import java.net.Inet4Address; 30 import java.net.Inet6Address; 31 import java.net.InetAddress; 32 import java.net.UnknownHostException; 33 import java.util.Arrays; 34 import java.util.Comparator; 35 36 /** 37 * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a 38 * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of 39 * information: 40 * 41 * <ul> 42 * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. 43 * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits 44 * in the IP address, starting from the most significant bit in network byte order, that 45 * are constant for all addresses in the prefix. 46 * </ul> 47 * 48 * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from 49 * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix 50 * <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to 51 * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive. 52 * 53 * Objects of this class are immutable. 54 */ 55 public final class IpPrefix implements Parcelable { 56 private final byte[] address; // network byte order 57 private final int prefixLength; 58 59 private void checkAndMaskAddressAndPrefixLength() { 60 if (address.length != 4 && address.length != 16) { 61 throw new IllegalArgumentException( 62 "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); 63 } 64 NetUtils.maskRawAddress(address, prefixLength); 65 } 66 67 /** 68 * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in 69 * network byte order and a prefix length. Silently truncates the address to the prefix length, 70 * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}. 71 * 72 * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. 73 * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 74 * 75 * @hide 76 */ 77 public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) { 78 this.address = address.clone(); 79 this.prefixLength = prefixLength; 80 checkAndMaskAddressAndPrefixLength(); 81 } 82 83 /** 84 * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently 85 * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently 86 * converted to {@code 192.0.2.0/24}. 87 * 88 * @param address the IP address. Must be non-null. 89 * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 90 * @hide 91 */ 92 @SystemApi 93 public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) { 94 // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, 95 // which is unnecessary because getAddress() already returns a clone. 96 this.address = address.getAddress(); 97 this.prefixLength = prefixLength; 98 checkAndMaskAddressAndPrefixLength(); 99 } 100 101 /** 102 * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". 103 * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} 104 * is silently converted to {@code 192.0.2.0/24}. 105 * 106 * @param prefix the prefix to parse 107 * 108 * @hide 109 */ 110 @SystemApi 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.legacyParseIpAndMask(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 130 public boolean equals(@Nullable 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 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 */ 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 */ 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) 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 */ 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 NetUtils.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 */ 206 public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { 207 if (otherPrefix.getPrefixLength() < prefixLength) return false; 208 final byte[] otherAddress = otherPrefix.getRawAddress(); 209 NetUtils.maskRawAddress(otherAddress, prefixLength); 210 return Arrays.equals(otherAddress, address); 211 } 212 213 /** 214 * @hide 215 */ 216 public boolean isIPv6() { 217 return getAddress() instanceof Inet6Address; 218 } 219 220 /** 221 * @hide 222 */ 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 */ 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 */ 244 public int describeContents() { 245 return 0; 246 } 247 248 /** 249 * Implement the Parcelable interface. 250 */ 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 */ 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