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 17package android.net; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.util.Pair; 22 23import java.net.Inet4Address; 24import java.net.Inet6Address; 25import java.net.InetAddress; 26import java.net.UnknownHostException; 27import java.util.Arrays; 28 29/** 30 * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a 31 * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of 32 * information: 33 * 34 * <ul> 35 * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. 36 * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits 37 * in the IP address, starting from the most significant bit in network byte order, that 38 * are constant for all addresses in the prefix. 39 * </ul> 40 * 41 * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from 42 * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix 43 * <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to 44 * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive. 45 * 46 * Objects of this class are immutable. 47 */ 48public final class IpPrefix implements Parcelable { 49 private final byte[] address; // network byte order 50 private final int prefixLength; 51 52 private void checkAndMaskAddressAndPrefixLength() { 53 if (address.length != 4 && address.length != 16) { 54 throw new IllegalArgumentException( 55 "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); 56 } 57 NetworkUtils.maskRawAddress(address, prefixLength); 58 } 59 60 /** 61 * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in 62 * network byte order and a prefix length. Silently truncates the address to the prefix length, 63 * so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}. 64 * 65 * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. 66 * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 67 * 68 * @hide 69 */ 70 public IpPrefix(byte[] address, int prefixLength) { 71 this.address = address.clone(); 72 this.prefixLength = prefixLength; 73 checkAndMaskAddressAndPrefixLength(); 74 } 75 76 /** 77 * Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently 78 * truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently 79 * converted to {@code 192.0.2.0/24}. 80 * 81 * @param address the IP address. Must be non-null. 82 * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 83 * @hide 84 */ 85 public IpPrefix(InetAddress address, int prefixLength) { 86 // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array, 87 // which is unnecessary because getAddress() already returns a clone. 88 this.address = address.getAddress(); 89 this.prefixLength = prefixLength; 90 checkAndMaskAddressAndPrefixLength(); 91 } 92 93 /** 94 * Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64". 95 * Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24} 96 * is silently converted to {@code 192.0.2.0/24}. 97 * 98 * @param prefix the prefix to parse 99 * 100 * @hide 101 */ 102 public IpPrefix(String prefix) { 103 // We don't reuse the (InetAddress, int) constructor because "error: call to this must be 104 // first statement in constructor". We could factor out setting the member variables to an 105 // init() method, but if we did, then we'd have to make the members non-final, or "error: 106 // cannot assign a value to final variable address". So we just duplicate the code here. 107 Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix); 108 this.address = ipAndMask.first.getAddress(); 109 this.prefixLength = ipAndMask.second; 110 checkAndMaskAddressAndPrefixLength(); 111 } 112 113 /** 114 * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two 115 * objects are equal if they have the same startAddress and prefixLength. 116 * 117 * @param obj the object to be tested for equality. 118 * @return {@code true} if both objects are equal, {@code false} otherwise. 119 */ 120 @Override 121 public boolean equals(Object obj) { 122 if (!(obj instanceof IpPrefix)) { 123 return false; 124 } 125 IpPrefix that = (IpPrefix) obj; 126 return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; 127 } 128 129 /** 130 * Gets the hashcode of the represented IP prefix. 131 * 132 * @return the appropriate hashcode value. 133 */ 134 @Override 135 public int hashCode() { 136 return Arrays.hashCode(address) + 11 * prefixLength; 137 } 138 139 /** 140 * Returns a copy of the first IP address in the prefix. Modifying the returned object does not 141 * change this object's contents. 142 * 143 * @return the address in the form of a byte array. 144 */ 145 public InetAddress getAddress() { 146 try { 147 return InetAddress.getByAddress(address); 148 } catch (UnknownHostException e) { 149 // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte 150 // array is the wrong length, but we check that in the constructor. 151 return null; 152 } 153 } 154 155 /** 156 * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth 157 * element). Modifying the returned array does not change this object's contents. 158 * 159 * @return the address in the form of a byte array. 160 */ 161 public byte[] getRawAddress() { 162 return address.clone(); 163 } 164 165 /** 166 * Returns the prefix length of this {@code IpPrefix}. 167 * 168 * @return the prefix length. 169 */ 170 public int getPrefixLength() { 171 return prefixLength; 172 } 173 174 /** 175 * Determines whether the prefix contains the specified address. 176 * 177 * @param address An {@link InetAddress} to test. 178 * @return {@code true} if the prefix covers the given address. 179 */ 180 public boolean contains(InetAddress address) { 181 byte[] addrBytes = (address == null) ? null : address.getAddress(); 182 if (addrBytes == null || addrBytes.length != this.address.length) { 183 return false; 184 } 185 NetworkUtils.maskRawAddress(addrBytes, prefixLength); 186 return Arrays.equals(this.address, addrBytes); 187 } 188 189 /** 190 * @hide 191 */ 192 public boolean isIPv6() { 193 return getAddress() instanceof Inet6Address; 194 } 195 196 /** 197 * @hide 198 */ 199 public boolean isIPv4() { 200 return getAddress() instanceof Inet4Address; 201 } 202 203 /** 204 * Returns a string representation of this {@code IpPrefix}. 205 * 206 * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. 207 */ 208 public String toString() { 209 try { 210 return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength; 211 } catch(UnknownHostException e) { 212 // Cosmic rays? 213 throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e); 214 } 215 } 216 217 /** 218 * Implement the Parcelable interface. 219 */ 220 public int describeContents() { 221 return 0; 222 } 223 224 /** 225 * Implement the Parcelable interface. 226 */ 227 public void writeToParcel(Parcel dest, int flags) { 228 dest.writeByteArray(address); 229 dest.writeInt(prefixLength); 230 } 231 232 /** 233 * Implement the Parcelable interface. 234 */ 235 public static final Creator<IpPrefix> CREATOR = 236 new Creator<IpPrefix>() { 237 public IpPrefix createFromParcel(Parcel in) { 238 byte[] address = in.createByteArray(); 239 int prefixLength = in.readInt(); 240 return new IpPrefix(address, prefixLength); 241 } 242 243 public IpPrefix[] newArray(int size) { 244 return new IpPrefix[size]; 245 } 246 }; 247} 248