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 static android.system.OsConstants.IFA_F_DADFAILED;
20 import static android.system.OsConstants.IFA_F_DEPRECATED;
21 import static android.system.OsConstants.IFA_F_OPTIMISTIC;
22 import static android.system.OsConstants.IFA_F_PERMANENT;
23 import static android.system.OsConstants.IFA_F_TENTATIVE;
24 import static android.system.OsConstants.RT_SCOPE_HOST;
25 import static android.system.OsConstants.RT_SCOPE_LINK;
26 import static android.system.OsConstants.RT_SCOPE_SITE;
27 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
28 
29 import android.annotation.IntRange;
30 import android.annotation.NonNull;
31 import android.annotation.Nullable;
32 import android.annotation.SystemApi;
33 import android.compat.annotation.UnsupportedAppUsage;
34 import android.os.Build;
35 import android.os.Parcel;
36 import android.os.Parcelable;
37 import android.os.SystemClock;
38 import android.util.Pair;
39 
40 import com.android.net.module.util.ConnectivityUtils;
41 
42 import java.net.Inet4Address;
43 import java.net.Inet6Address;
44 import java.net.InetAddress;
45 import java.net.InterfaceAddress;
46 import java.net.UnknownHostException;
47 import java.util.Objects;
48 
49 /**
50  * Identifies an IP address on a network link.
51  *
52  * A {@code LinkAddress} consists of:
53  * <ul>
54  * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
55  * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
56  * <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties
57  * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}).
58  * <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which
59  * the address is unique (e.g.,
60  * {@code android.system.OsConstants.RT_SCOPE_LINK} or
61  * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}).
62  * </ul>
63  */
64 public class LinkAddress implements Parcelable {
65 
66     /**
67      * Indicates the deprecation or expiration time is unknown
68      * @hide
69      */
70     @SystemApi
71     public static final long LIFETIME_UNKNOWN = -1;
72 
73     /**
74      * Indicates this address is permanent.
75      * @hide
76      */
77     @SystemApi
78     public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;
79 
80     /**
81      * IPv4 or IPv6 address.
82      */
83     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
84     private InetAddress address;
85 
86     /**
87      * Prefix length.
88      */
89     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
90     private int prefixLength;
91 
92     /**
93      * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
94      * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
95      * flag depending on the current preferred lifetime.
96      */
97     private int flags;
98 
99     /**
100      * Address scope. One of the RT_SCOPE_* constants.
101      */
102     private int scope;
103 
104     /**
105      * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
106      * or was deprecated. At the time existing connections can still use this address until it
107      * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates
108      * this information is not available. {@link #LIFETIME_PERMANENT} indicates this
109      * {@link LinkAddress} will never be deprecated.
110      */
111     private long deprecationTime;
112 
113     /**
114      * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
115      * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
116      * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
117      * will never expire.
118      */
119     private long expirationTime;
120 
121     /**
122      * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
123      * RFC 6724 section 3.2.
124      * @hide
125      */
scopeForUnicastAddress(InetAddress addr)126     private static int scopeForUnicastAddress(InetAddress addr) {
127         if (addr.isAnyLocalAddress()) {
128             return RT_SCOPE_HOST;
129         }
130 
131         if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
132             return RT_SCOPE_LINK;
133         }
134 
135         // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
136         // says that they are assigned global scope.
137         if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
138             return RT_SCOPE_SITE;
139         }
140 
141         return RT_SCOPE_UNIVERSE;
142     }
143 
144     /**
145      * Utility function to check if |address| is a Unique Local IPv6 Unicast Address
146      * (a.k.a. "ULA"; RFC 4193).
147      *
148      * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
149      */
isIpv6ULA()150     private boolean isIpv6ULA() {
151         return ConnectivityUtils.isIPv6ULA(address);
152     }
153 
154     /**
155      * @return true if the address is IPv6.
156      * @hide
157      */
158     @SystemApi
isIpv6()159     public boolean isIpv6() {
160         return address instanceof Inet6Address;
161     }
162 
163     /**
164      * For backward compatibility.
165      * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
166      * just yet.
167      * @return true if the address is IPv6.
168      * @hide
169      */
170     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
isIPv6()171     public boolean isIPv6() {
172         return isIpv6();
173     }
174 
175     /**
176      * @return true if the address is IPv4 or is a mapped IPv4 address.
177      * @hide
178      */
179     @SystemApi
isIpv4()180     public boolean isIpv4() {
181         return address instanceof Inet4Address;
182     }
183 
184     /**
185      * Utility function for the constructors.
186      */
init(InetAddress address, int prefixLength, int flags, int scope, long deprecationTime, long expirationTime)187     private void init(InetAddress address, int prefixLength, int flags, int scope,
188                       long deprecationTime, long expirationTime) {
189         if (address == null ||
190                 address.isMulticastAddress() ||
191                 prefixLength < 0 ||
192                 (address instanceof Inet4Address && prefixLength > 32) ||
193                 (prefixLength > 128)) {
194             throw new IllegalArgumentException("Bad LinkAddress params " + address +
195                     "/" + prefixLength);
196         }
197 
198         // deprecation time and expiration time must be both provided, or neither.
199         if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
200             throw new IllegalArgumentException(
201                     "Must not specify only one of deprecation time and expiration time");
202         }
203 
204         // deprecation time needs to be a positive value.
205         if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
206             throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
207         }
208 
209         // expiration time needs to be a positive value.
210         if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
211             throw new IllegalArgumentException("invalid expiration time " + expirationTime);
212         }
213 
214         // expiration time can't be earlier than deprecation time
215         if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
216                 && expirationTime < deprecationTime) {
217             throw new IllegalArgumentException("expiration earlier than deprecation ("
218                     + deprecationTime + ", " + expirationTime + ")");
219         }
220 
221         this.address = address;
222         this.prefixLength = prefixLength;
223         this.flags = flags;
224         this.scope = scope;
225         this.deprecationTime = deprecationTime;
226         this.expirationTime = expirationTime;
227     }
228 
229     /**
230      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
231      * the specified flags and scope. Flags and scope are not checked for validity.
232      *
233      * @param address The IP address.
234      * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
235      * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
236      * @param scope An integer defining the scope in which the address is unique (e.g.,
237      *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
238      * @hide
239      */
240     @SystemApi
LinkAddress(@onNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, int flags, int scope)241     public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
242             int flags, int scope) {
243         init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
244     }
245 
246     /**
247      * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
248      * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
249      * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
250      * flag will be adjusted based on the passed-in lifetimes.
251      *
252      * @param address The IP address.
253      * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
254      * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
255      * @param scope An integer defining the scope in which the address is unique (e.g.,
256      *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
257      * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
258      *                        this {@link LinkAddress} will be or was deprecated. At the time
259      *                        existing connections can still use this address until it expires, but
260      *                        new connections should use the new address. {@link #LIFETIME_UNKNOWN}
261      *                        indicates this information is not available.
262      *                        {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
263      *                        never be deprecated.
264      * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
265      *                       {@link LinkAddress} will expire and be removed from the interface.
266      *                       {@link #LIFETIME_UNKNOWN} indicates this information is not available.
267      *                       {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
268      *                       never expire.
269      * @hide
270      */
271     @SystemApi
LinkAddress(@onNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, int flags, int scope, long deprecationTime, long expirationTime)272     public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
273                        int flags, int scope, long deprecationTime, long expirationTime) {
274         init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
275     }
276 
277     /**
278      * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
279      * The flags are set to zero and the scope is determined from the address.
280      * @param address The IP address.
281      * @param prefixLength The prefix length. Must be &gt;= 0 and &lt;= (32 or 128) (IPv4 or IPv6).
282      * @hide
283      */
284     @SystemApi
LinkAddress(@onNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength)285     public LinkAddress(@NonNull InetAddress address,
286             @IntRange(from = 0, to = 128) int prefixLength) {
287         this(address, prefixLength, 0, 0);
288         this.scope = scopeForUnicastAddress(address);
289     }
290 
291     /**
292      * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
293      * The flags are set to zero and the scope is determined from the address.
294      * @param interfaceAddress The interface address.
295      * @hide
296      */
LinkAddress(@onNull InterfaceAddress interfaceAddress)297     public LinkAddress(@NonNull InterfaceAddress interfaceAddress) {
298         this(interfaceAddress.getAddress(),
299              interfaceAddress.getNetworkPrefixLength());
300     }
301 
302     /**
303      * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
304      * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
305      * @param address The string to parse.
306      * @hide
307      */
308     @SystemApi
LinkAddress(@onNull String address)309     public LinkAddress(@NonNull String address) {
310         this(address, 0, 0);
311         this.scope = scopeForUnicastAddress(this.address);
312     }
313 
314     /**
315      * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
316      * "2001:db8::1/64", with the specified flags and scope.
317      * @param address The string to parse.
318      * @param flags The address flags.
319      * @param scope The address scope.
320      * @hide
321      */
322     @SystemApi
LinkAddress(@onNull String address, int flags, int scope)323     public LinkAddress(@NonNull String address, int flags, int scope) {
324         // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
325         // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
326         Pair<InetAddress, Integer> ipAndMask = NetworkUtils.legacyParseIpAndMask(address);
327         init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
328     }
329 
330     /**
331      * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
332      * The string representation does not contain the flags and scope, just the address and prefix
333      * length.
334      */
335     @Override
toString()336     public String toString() {
337         return address.getHostAddress() + "/" + prefixLength;
338     }
339 
340     /**
341      * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
342      * their address, prefix length, flags and scope are equal. Thus, for example, two addresses
343      * that have the same address and prefix length are not equal if one of them is deprecated and
344      * the other is not.
345      *
346      * @param obj the object to be tested for equality.
347      * @return {@code true} if both objects are equal, {@code false} otherwise.
348      */
349     @Override
equals(@ullable Object obj)350     public boolean equals(@Nullable Object obj) {
351         if (!(obj instanceof LinkAddress)) {
352             return false;
353         }
354         LinkAddress linkAddress = (LinkAddress) obj;
355         return this.address.equals(linkAddress.address)
356                 && this.prefixLength == linkAddress.prefixLength
357                 && this.flags == linkAddress.flags
358                 && this.scope == linkAddress.scope
359                 && this.deprecationTime == linkAddress.deprecationTime
360                 && this.expirationTime == linkAddress.expirationTime;
361     }
362 
363     /**
364      * Returns a hashcode for this address.
365      */
366     @Override
hashCode()367     public int hashCode() {
368         return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
369     }
370 
371     /**
372      * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress}
373      * represent the same address. Two {@code LinkAddresses} represent the same address
374      * if they have the same IP address and prefix length, even if their properties are
375      * different.
376      *
377      * @param other the {@code LinkAddress} to compare to.
378      * @return {@code true} if both objects have the same address and prefix length, {@code false}
379      * otherwise.
380      * @hide
381      */
382     @SystemApi
isSameAddressAs(@ullable LinkAddress other)383     public boolean isSameAddressAs(@Nullable LinkAddress other) {
384         if (other == null) {
385             return false;
386         }
387         return address.equals(other.address) && prefixLength == other.prefixLength;
388     }
389 
390     /**
391      * Returns the {@link InetAddress} of this {@code LinkAddress}.
392      */
getAddress()393     public InetAddress getAddress() {
394         return address;
395     }
396 
397     /**
398      * Returns the prefix length of this {@code LinkAddress}.
399      */
400     @IntRange(from = 0, to = 128)
getPrefixLength()401     public int getPrefixLength() {
402         return prefixLength;
403     }
404 
405     /**
406      * Returns the prefix length of this {@code LinkAddress}.
407      * TODO: Delete all callers and remove in favour of getPrefixLength().
408      * @hide
409      */
410     @UnsupportedAppUsage
411     @IntRange(from = 0, to = 128)
getNetworkPrefixLength()412     public int getNetworkPrefixLength() {
413         return getPrefixLength();
414     }
415 
416     /**
417      * Returns the flags of this {@code LinkAddress}.
418      */
getFlags()419     public int getFlags() {
420         int flags = this.flags;
421         if (deprecationTime != LIFETIME_UNKNOWN) {
422             if (SystemClock.elapsedRealtime() >= deprecationTime) {
423                 flags |= IFA_F_DEPRECATED;
424             } else {
425                 // If deprecation time is in the future, or permanent.
426                 flags &= ~IFA_F_DEPRECATED;
427             }
428         }
429 
430         if (expirationTime == LIFETIME_PERMANENT) {
431             flags |= IFA_F_PERMANENT;
432         } else if (expirationTime != LIFETIME_UNKNOWN) {
433             // If we know this address expired or will expire in the future, then this address
434             // should not be permanent.
435             flags &= ~IFA_F_PERMANENT;
436         }
437 
438         // Do no touch the original flags. Return the adjusted flags here.
439         return flags;
440     }
441 
442     /**
443      * Returns the scope of this {@code LinkAddress}.
444      */
getScope()445     public int getScope() {
446         return scope;
447     }
448 
449     /**
450      * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this
451      * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use
452      * this address until it expires, but new connections should use the new address.
453      *
454      * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
455      * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
456      * will never be deprecated.
457      *
458      * @hide
459      */
460     @SystemApi
getDeprecationTime()461     public long getDeprecationTime() {
462         return deprecationTime;
463     }
464 
465     /**
466      * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this
467      * {@link LinkAddress} will expire and be removed from the interface.
468      *
469      * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
470      * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
471      * will never expire.
472      *
473      * @hide
474      */
475     @SystemApi
getExpirationTime()476     public long getExpirationTime() {
477         return expirationTime;
478     }
479 
480     /**
481      * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
482      * deprecated).
483      *
484      * @hide
485      */
486     @SystemApi
isGlobalPreferred()487     public boolean isGlobalPreferred() {
488         return (scope == RT_SCOPE_UNIVERSE
489                 && !isIpv6ULA()
490                 && isPreferred());
491     }
492 
493     /**
494      * Checks if the address is a preferred address.
495      *
496      * @hide
497      */
isPreferred()498     public boolean isPreferred() {
499         //  Note that addresses flagged as IFA_F_OPTIMISTIC are simultaneously flagged as
500         //  IFA_F_TENTATIVE (when the tentative state has cleared either DAD has succeeded or
501         //  failed, and both flags are cleared regardless).
502         int flags = getFlags();
503         return (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
504                 && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L);
505     }
506 
507     /**
508      * Implement the Parcelable interface.
509      */
describeContents()510     public int describeContents() {
511         return 0;
512     }
513 
514     /**
515      * Implement the Parcelable interface.
516      */
writeToParcel(Parcel dest, int flags)517     public void writeToParcel(Parcel dest, int flags) {
518         dest.writeByteArray(address.getAddress());
519         dest.writeInt(prefixLength);
520         dest.writeInt(this.flags);
521         dest.writeInt(scope);
522         dest.writeLong(deprecationTime);
523         dest.writeLong(expirationTime);
524     }
525 
526     /**
527      * Implement the Parcelable interface.
528      */
529     public static final @android.annotation.NonNull Creator<LinkAddress> CREATOR =
530         new Creator<LinkAddress>() {
531             public LinkAddress createFromParcel(Parcel in) {
532                 InetAddress address = null;
533                 try {
534                     address = InetAddress.getByAddress(in.createByteArray());
535                 } catch (UnknownHostException e) {
536                     // Nothing we can do here. When we call the constructor, we'll throw an
537                     // IllegalArgumentException, because a LinkAddress can't have a null
538                     // InetAddress.
539                 }
540                 int prefixLength = in.readInt();
541                 int flags = in.readInt();
542                 int scope = in.readInt();
543                 long deprecationTime = in.readLong();
544                 long expirationTime = in.readLong();
545                 return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
546                         expirationTime);
547             }
548 
549             public LinkAddress[] newArray(int size) {
550                 return new LinkAddress[size];
551             }
552         };
553 }
554