blob: 6e2654e3ce7c45f6bfefabef240b0d88e080603a [file] [log] [blame]
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -07001/*
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;
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +090021import android.util.Pair;
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070022
Hugo Benichi1dfb6b62017-08-08 13:06:04 +090023import java.net.Inet4Address;
24import java.net.Inet6Address;
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070025import 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 */
Robert Greenwalt0cbe94a2014-06-12 12:57:19 -070048public final class IpPrefix implements Parcelable {
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070049 private final byte[] address; // network byte order
50 private final int prefixLength;
51
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +090052 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
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070060 /**
61 * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +090062 * 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}.
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070064 *
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 &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
67 *
68 * @hide
69 */
70 public IpPrefix(byte[] address, int prefixLength) {
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070071 this.address = address.clone();
72 this.prefixLength = prefixLength;
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +090073 checkAndMaskAddressAndPrefixLength();
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070074 }
75
76 /**
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +090077 * 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 &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -070083 * @hide
84 */
85 public IpPrefix(InetAddress address, int prefixLength) {
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +090086 // 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();
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700111 }
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 /**
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +0900166 * Returns the prefix length of this {@code IpPrefix}.
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700167 *
168 * @return the prefix length.
169 */
170 public int getPrefixLength() {
171 return prefixLength;
172 }
173
174 /**
Erik Klineacc8c092015-04-13 15:33:34 +0900175 * 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 /**
Hugo Benichi1dfb6b62017-08-08 13:06:04 +0900190 * @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 /**
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +0900204 * Returns a string representation of this {@code IpPrefix}.
205 *
Lorenzo Colitti4b0f8e62014-09-19 01:49:05 +0900206 * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
Lorenzo Colitti8c6c2c32014-06-12 13:41:17 +0900207 */
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 /**
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700218 * Implement the Parcelable interface.
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700219 */
220 public int describeContents() {
221 return 0;
222 }
223
224 /**
225 * Implement the Parcelable interface.
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700226 */
227 public void writeToParcel(Parcel dest, int flags) {
228 dest.writeByteArray(address);
229 dest.writeInt(prefixLength);
230 }
231
232 /**
233 * Implement the Parcelable interface.
Sreeram Ramachandrancc91c7b2014-06-03 18:41:43 -0700234 */
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}