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 >= 0 and <= (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 >= 0 and <= (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 >= 0 and <= (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