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