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 checkAndMaskAddressAndPrefixLength()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 */ IpPrefix(@onNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength)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 */ IpPrefix(@onNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength)91 public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) { 92 // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, 93 // which is unnecessary because getAddress() already returns a clone. 94 this.address = address.getAddress(); 95 this.prefixLength = prefixLength; 96 checkAndMaskAddressAndPrefixLength(); 97 } 98 99 /** 100 * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". 101 * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} 102 * is silently converted to {@code 192.0.2.0/24}. 103 * 104 * @param prefix the prefix to parse 105 * 106 * @hide 107 */ 108 @SystemApi IpPrefix(@onNull String prefix)109 public IpPrefix(@NonNull String prefix) { 110 // We don't reuse the (InetAddress, int) constructor because "error: call to this must be 111 // first statement in constructor". We could factor out setting the member variables to an 112 // init() method, but if we did, then we'd have to make the members non-final, or "error: 113 // cannot assign a value to final variable address". So we just duplicate the code here. 114 Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(prefix); 115 this.address = ipAndMask.first.getAddress(); 116 this.prefixLength = ipAndMask.second; 117 checkAndMaskAddressAndPrefixLength(); 118 } 119 120 /** 121 * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two 122 * objects are equal if they have the same startAddress and prefixLength. 123 * 124 * @param obj the object to be tested for equality. 125 * @return {@code true} if both objects are equal, {@code false} otherwise. 126 */ 127 @Override equals(@ullable Object obj)128 public boolean equals(@Nullable Object obj) { 129 if (!(obj instanceof IpPrefix)) { 130 return false; 131 } 132 IpPrefix that = (IpPrefix) obj; 133 return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; 134 } 135 136 /** 137 * Gets the hashcode of the represented IP prefix. 138 * 139 * @return the appropriate hashcode value. 140 */ 141 @Override hashCode()142 public int hashCode() { 143 return Arrays.hashCode(address) + 11 * prefixLength; 144 } 145 146 /** 147 * Returns a copy of the first IP address in the prefix. Modifying the returned object does not 148 * change this object's contents. 149 * 150 * @return the address in the form of a byte array. 151 */ getAddress()152 public @NonNull InetAddress getAddress() { 153 try { 154 return InetAddress.getByAddress(address); 155 } catch (UnknownHostException e) { 156 // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte 157 // array is the wrong length, but we check that in the constructor. 158 throw new IllegalArgumentException("Address is invalid"); 159 } 160 } 161 162 /** 163 * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth 164 * element). Modifying the returned array does not change this object's contents. 165 * 166 * @return the address in the form of a byte array. 167 */ getRawAddress()168 public @NonNull byte[] getRawAddress() { 169 return address.clone(); 170 } 171 172 /** 173 * Returns the prefix length of this {@code IpPrefix}. 174 * 175 * @return the prefix length. 176 */ 177 @IntRange(from = 0, to = 128) getPrefixLength()178 public int getPrefixLength() { 179 return prefixLength; 180 } 181 182 /** 183 * Determines whether the prefix contains the specified address. 184 * 185 * @param address An {@link InetAddress} to test. 186 * @return {@code true} if the prefix covers the given address. {@code false} otherwise. 187 */ contains(@onNull InetAddress address)188 public boolean contains(@NonNull InetAddress address) { 189 byte[] addrBytes = address.getAddress(); 190 if (addrBytes == null || addrBytes.length != this.address.length) { 191 return false; 192 } 193 NetUtils.maskRawAddress(addrBytes, prefixLength); 194 return Arrays.equals(this.address, addrBytes); 195 } 196 197 /** 198 * Returns whether the specified prefix is entirely contained in this prefix. 199 * 200 * Note this is mathematical inclusion, so a prefix is always contained within itself. 201 * @param otherPrefix the prefix to test 202 * @hide 203 */ containsPrefix(@onNull IpPrefix otherPrefix)204 public boolean containsPrefix(@NonNull IpPrefix otherPrefix) { 205 if (otherPrefix.getPrefixLength() < prefixLength) return false; 206 final byte[] otherAddress = otherPrefix.getRawAddress(); 207 NetUtils.maskRawAddress(otherAddress, prefixLength); 208 return Arrays.equals(otherAddress, address); 209 } 210 211 /** 212 * @hide 213 */ isIPv6()214 public boolean isIPv6() { 215 return getAddress() instanceof Inet6Address; 216 } 217 218 /** 219 * @hide 220 */ isIPv4()221 public boolean isIPv4() { 222 return getAddress() instanceof Inet4Address; 223 } 224 225 /** 226 * Returns a string representation of this {@code IpPrefix}. 227 * 228 * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. 229 */ toString()230 public String toString() { 231 try { 232 return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength; 233 } catch(UnknownHostException e) { 234 // Cosmic rays? 235 throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e); 236 } 237 } 238 239 /** 240 * Implement the Parcelable interface. 241 */ describeContents()242 public int describeContents() { 243 return 0; 244 } 245 246 /** 247 * Implement the Parcelable interface. 248 */ writeToParcel(Parcel dest, int flags)249 public void writeToParcel(Parcel dest, int flags) { 250 dest.writeByteArray(address); 251 dest.writeInt(prefixLength); 252 } 253 254 /** 255 * Returns a comparator ordering IpPrefixes by length, shorter to longer. 256 * Contents of the address will break ties. 257 * @hide 258 */ lengthComparator()259 public static Comparator<IpPrefix> lengthComparator() { 260 return new Comparator<IpPrefix>() { 261 @Override 262 public int compare(IpPrefix prefix1, IpPrefix prefix2) { 263 if (prefix1.isIPv4()) { 264 if (prefix2.isIPv6()) return -1; 265 } else { 266 if (prefix2.isIPv4()) return 1; 267 } 268 final int p1len = prefix1.getPrefixLength(); 269 final int p2len = prefix2.getPrefixLength(); 270 if (p1len < p2len) return -1; 271 if (p2len < p1len) return 1; 272 final byte[] a1 = prefix1.address; 273 final byte[] a2 = prefix2.address; 274 final int len = a1.length < a2.length ? a1.length : a2.length; 275 for (int i = 0; i < len; ++i) { 276 if (a1[i] < a2[i]) return -1; 277 if (a1[i] > a2[i]) return 1; 278 } 279 if (a2.length < len) return 1; 280 if (a1.length < len) return -1; 281 return 0; 282 } 283 }; 284 } 285 286 /** 287 * Implement the Parcelable interface. 288 */ 289 public static final @android.annotation.NonNull Creator<IpPrefix> CREATOR = 290 new Creator<IpPrefix>() { 291 public IpPrefix createFromParcel(Parcel in) { 292 byte[] address = in.createByteArray(); 293 int prefixLength = in.readInt(); 294 return new IpPrefix(address, prefixLength); 295 } 296 297 public IpPrefix[] newArray(int size) { 298 return new IpPrefix[size]; 299 } 300 }; 301 } 302