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