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.os.Parcel;
20 import android.os.Parcelable;
21 
22 import java.net.InetAddress;
23 import java.net.UnknownHostException;
24 import java.util.Arrays;
25 
26 /**
27  * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
28  * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of
29  * information:
30  *
31  * <ul>
32  * <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix.
33  * <li>A prefix length. This specifies the length of the prefix by specifing the number of bits
34  *     in the IP address, starting from the most significant bit in network byte order, that
35  *     are constant for all addresses in the prefix.
36  * </ul>
37  *
38  * For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from
39  * <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix
40  * <code>2001:db8:1:2</code>  covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to
41  * <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive.
42  *
43  * Objects of this class are immutable.
44  */
45 public class IpPrefix implements Parcelable {
46     private final byte[] address;  // network byte order
47     private final int prefixLength;
48 
49     /**
50      * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
51      * network byte order and a prefix length.
52      *
53      * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long.
54      * @param prefixLength the prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
55      *
56      * @hide
57      */
58     public IpPrefix(byte[] address, int prefixLength) {
59         if (address.length != 4 && address.length != 16) {
60             throw new IllegalArgumentException(
61                     "IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
62         }
63         if (prefixLength < 0 || prefixLength > (address.length * 8)) {
64             throw new IllegalArgumentException("IpPrefix with " + address.length +
65                     " bytes has invalid prefix length " + prefixLength);
66         }
67         this.address = address.clone();
68         this.prefixLength = prefixLength;
69         // TODO: Validate that the non-prefix bits are zero
70     }
71 
72     /**
73      * @hide
74      */
75     public IpPrefix(InetAddress address, int prefixLength) {
76         this(address.getAddress(), prefixLength);
77     }
78 
79     /**
80      * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two
81      * objects are equal if they have the same startAddress and prefixLength.
82      *
83      * @param obj the object to be tested for equality.
84      * @return {@code true} if both objects are equal, {@code false} otherwise.
85      */
86     @Override
87     public boolean equals(Object obj) {
88         if (!(obj instanceof IpPrefix)) {
89             return false;
90         }
91         IpPrefix that = (IpPrefix) obj;
92         return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength;
93     }
94 
95     /**
96      * Gets the hashcode of the represented IP prefix.
97      *
98      * @return the appropriate hashcode value.
99      */
100     @Override
101     public int hashCode() {
102         return Arrays.hashCode(address) + 11 * prefixLength;
103     }
104 
105     /**
106      * Returns a copy of the first IP address in the prefix. Modifying the returned object does not
107      * change this object's contents.
108      *
109      * @return the address in the form of a byte array.
110      */
111     public InetAddress getAddress() {
112         try {
113             return InetAddress.getByAddress(address);
114         } catch (UnknownHostException e) {
115             // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
116             // array is the wrong length, but we check that in the constructor.
117             return null;
118         }
119     }
120 
121     /**
122      * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth
123      * element). Modifying the returned array does not change this object's contents.
124      *
125      * @return the address in the form of a byte array.
126      */
127     public byte[] getRawAddress() {
128         return address.clone();
129     }
130 
131     /**
132      * Returns the prefix length of this {@code IpAddress}.
133      *
134      * @return the prefix length.
135      */
136     public int getPrefixLength() {
137         return prefixLength;
138     }
139 
140     /**
141      * Implement the Parcelable interface.
142      * @hide
143      */
144     public int describeContents() {
145         return 0;
146     }
147 
148     /**
149      * Implement the Parcelable interface.
150      * @hide
151      */
152     public void writeToParcel(Parcel dest, int flags) {
153         dest.writeByteArray(address);
154         dest.writeInt(prefixLength);
155     }
156 
157     /**
158      * Implement the Parcelable interface.
159      * @hide
160      */
161     public static final Creator<IpPrefix> CREATOR =
162             new Creator<IpPrefix>() {
163                 public IpPrefix createFromParcel(Parcel in) {
164                     byte[] address = in.createByteArray();
165                     int prefixLength = in.readInt();
166                     return new IpPrefix(address, prefixLength);
167                 }
168 
169                 public IpPrefix[] newArray(int size) {
170                     return new IpPrefix[size];
171                 }
172             };
173 }
174