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