1 /*
2  * Copyright (C) 2010 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.Inet4Address;
23 import java.net.InetAddress;
24 import java.net.InterfaceAddress;
25 import java.net.UnknownHostException;
26 
27 import static android.system.OsConstants.IFA_F_DADFAILED;
28 import static android.system.OsConstants.IFA_F_DEPRECATED;
29 import static android.system.OsConstants.IFA_F_TENTATIVE;
30 import static android.system.OsConstants.RT_SCOPE_HOST;
31 import static android.system.OsConstants.RT_SCOPE_LINK;
32 import static android.system.OsConstants.RT_SCOPE_SITE;
33 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
34 
35 /**
36  * Identifies an IP address on a network link.
37  *
38  * A {@code LinkAddress} consists of:
39  * <ul>
40  * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
41  * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
42  * <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties
43  * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}).
44  * <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which
45  * the address is unique (e.g.,
46  * {@code android.system.OsConstants.RT_SCOPE_LINK} or
47  * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}).
48  * </ul>
49  */
50 public class LinkAddress implements Parcelable {
51     /**
52      * IPv4 or IPv6 address.
53      */
54     private InetAddress address;
55 
56     /**
57      * Prefix length.
58      */
59     private int prefixLength;
60 
61     /**
62      * Address flags. A bitmask of IFA_F_* values.
63      */
64     private int flags;
65 
66     /**
67      * Address scope. One of the RT_SCOPE_* constants.
68      */
69     private int scope;
70 
71     /**
72      * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
73      * RFC 6724 section 3.2.
74      * @hide
75      */
scopeForUnicastAddress(InetAddress addr)76     static int scopeForUnicastAddress(InetAddress addr) {
77         if (addr.isAnyLocalAddress()) {
78             return RT_SCOPE_HOST;
79         }
80 
81         if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
82             return RT_SCOPE_LINK;
83         }
84 
85         // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
86         // says that they are assigned global scope.
87         if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
88             return RT_SCOPE_SITE;
89         }
90 
91         return RT_SCOPE_UNIVERSE;
92     }
93 
94     /**
95      * Utility function for the constructors.
96      */
init(InetAddress address, int prefixLength, int flags, int scope)97     private void init(InetAddress address, int prefixLength, int flags, int scope) {
98         if (address == null ||
99                 address.isMulticastAddress() ||
100                 prefixLength < 0 ||
101                 ((address instanceof Inet4Address) && prefixLength > 32) ||
102                 (prefixLength > 128)) {
103             throw new IllegalArgumentException("Bad LinkAddress params " + address +
104                     "/" + prefixLength);
105         }
106         this.address = address;
107         this.prefixLength = prefixLength;
108         this.flags = flags;
109         this.scope = scope;
110     }
111 
112     /**
113      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
114      * the specified flags and scope. Flags and scope are not checked for validity.
115      * @param address The IP address.
116      * @param prefixLength The prefix length.
117      * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
118      * @param scope An integer defining the scope in which the address is unique (e.g.,
119      *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
120      * @hide
121      */
LinkAddress(InetAddress address, int prefixLength, int flags, int scope)122     public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
123         init(address, prefixLength, flags, scope);
124     }
125 
126     /**
127      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
128      * The flags are set to zero and the scope is determined from the address.
129      * @param address The IP address.
130      * @param prefixLength The prefix length.
131      * @hide
132      */
LinkAddress(InetAddress address, int prefixLength)133     public LinkAddress(InetAddress address, int prefixLength) {
134         this(address, prefixLength, 0, 0);
135         this.scope = scopeForUnicastAddress(address);
136     }
137 
138     /**
139      * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
140      * The flags are set to zero and the scope is determined from the address.
141      * @param interfaceAddress The interface address.
142      * @hide
143      */
LinkAddress(InterfaceAddress interfaceAddress)144     public LinkAddress(InterfaceAddress interfaceAddress) {
145         this(interfaceAddress.getAddress(),
146              interfaceAddress.getNetworkPrefixLength());
147     }
148 
149     /**
150      * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
151      * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
152      * @param string The string to parse.
153      * @hide
154      */
LinkAddress(String address)155     public LinkAddress(String address) {
156         this(address, 0, 0);
157         this.scope = scopeForUnicastAddress(this.address);
158     }
159 
160     /**
161      * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
162      * "2001:db8::1/64", with the specified flags and scope.
163      * @param string The string to parse.
164      * @param flags The address flags.
165      * @param scope The address scope.
166      * @hide
167      */
LinkAddress(String address, int flags, int scope)168     public LinkAddress(String address, int flags, int scope) {
169         InetAddress inetAddress = null;
170         int prefixLength = -1;
171         try {
172             String [] pieces = address.split("/", 2);
173             prefixLength = Integer.parseInt(pieces[1]);
174             inetAddress = InetAddress.parseNumericAddress(pieces[0]);
175         } catch (NullPointerException e) {            // Null string.
176         } catch (ArrayIndexOutOfBoundsException e) {  // No prefix length.
177         } catch (NumberFormatException e) {           // Non-numeric prefix.
178         } catch (IllegalArgumentException e) {        // Invalid IP address.
179         }
180 
181         if (inetAddress == null || prefixLength == -1) {
182             throw new IllegalArgumentException("Bad LinkAddress params " + address);
183         }
184 
185         init(inetAddress, prefixLength, flags, scope);
186     }
187 
188     /**
189      * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
190      * The string representation does not contain the flags and scope, just the address and prefix
191      * length.
192      */
193     @Override
toString()194     public String toString() {
195         return address.getHostAddress() + "/" + prefixLength;
196     }
197 
198     /**
199      * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
200      * their address, prefix length, flags and scope are equal. Thus, for example, two addresses
201      * that have the same address and prefix length are not equal if one of them is deprecated and
202      * the other is not.
203      *
204      * @param obj the object to be tested for equality.
205      * @return {@code true} if both objects are equal, {@code false} otherwise.
206      */
207     @Override
equals(Object obj)208     public boolean equals(Object obj) {
209         if (!(obj instanceof LinkAddress)) {
210             return false;
211         }
212         LinkAddress linkAddress = (LinkAddress) obj;
213         return this.address.equals(linkAddress.address) &&
214             this.prefixLength == linkAddress.prefixLength &&
215             this.flags == linkAddress.flags &&
216             this.scope == linkAddress.scope;
217     }
218 
219     /**
220      * Returns a hashcode for this address.
221      */
222     @Override
hashCode()223     public int hashCode() {
224         return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
225     }
226 
227     /**
228      * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress}
229      * represent the same address. Two {@code LinkAddresses} represent the same address
230      * if they have the same IP address and prefix length, even if their properties are
231      * different.
232      *
233      * @param other the {@code LinkAddress} to compare to.
234      * @return {@code true} if both objects have the same address and prefix length, {@code false}
235      * otherwise.
236      * @hide
237      */
isSameAddressAs(LinkAddress other)238     public boolean isSameAddressAs(LinkAddress other) {
239         return address.equals(other.address) && prefixLength == other.prefixLength;
240     }
241 
242     /**
243      * Returns the {@link InetAddress} of this {@code LinkAddress}.
244      */
getAddress()245     public InetAddress getAddress() {
246         return address;
247     }
248 
249     /**
250      * Returns the prefix length of this {@code LinkAddress}.
251      */
getPrefixLength()252     public int getPrefixLength() {
253         return prefixLength;
254     }
255 
256     /**
257      * Returns the prefix length of this {@code LinkAddress}.
258      * TODO: Delete all callers and remove in favour of getPrefixLength().
259      * @hide
260      */
getNetworkPrefixLength()261     public int getNetworkPrefixLength() {
262         return getPrefixLength();
263     }
264 
265     /**
266      * Returns the flags of this {@code LinkAddress}.
267      */
getFlags()268     public int getFlags() {
269         return flags;
270     }
271 
272     /**
273      * Returns the scope of this {@code LinkAddress}.
274      */
getScope()275     public int getScope() {
276         return scope;
277     }
278 
279     /**
280      * Returns true if this {@code LinkAddress} is global scope and preferred.
281      * @hide
282      */
isGlobalPreferred()283     public boolean isGlobalPreferred() {
284         return (scope == RT_SCOPE_UNIVERSE &&
285                 (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L);
286     }
287 
288     /**
289      * Implement the Parcelable interface.
290      * @hide
291      */
describeContents()292     public int describeContents() {
293         return 0;
294     }
295 
296     /**
297      * Implement the Parcelable interface.
298      * @hide
299      */
writeToParcel(Parcel dest, int flags)300     public void writeToParcel(Parcel dest, int flags) {
301         dest.writeByteArray(address.getAddress());
302         dest.writeInt(prefixLength);
303         dest.writeInt(this.flags);
304         dest.writeInt(scope);
305     }
306 
307     /**
308      * Implement the Parcelable interface.
309      * @hide
310      */
311     public static final Creator<LinkAddress> CREATOR =
312         new Creator<LinkAddress>() {
313             public LinkAddress createFromParcel(Parcel in) {
314                 InetAddress address = null;
315                 try {
316                     address = InetAddress.getByAddress(in.createByteArray());
317                 } catch (UnknownHostException e) {
318                     // Nothing we can do here. When we call the constructor, we'll throw an
319                     // IllegalArgumentException, because a LinkAddress can't have a null
320                     // InetAddress.
321                 }
322                 int prefixLength = in.readInt();
323                 int flags = in.readInt();
324                 int scope = in.readInt();
325                 return new LinkAddress(address, prefixLength, flags, scope);
326             }
327 
328             public LinkAddress[] newArray(int size) {
329                 return new LinkAddress[size];
330             }
331         };
332 }
333