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_TENTATIVE; 23 import static android.system.OsConstants.RT_SCOPE_HOST; 24 import static android.system.OsConstants.RT_SCOPE_LINK; 25 import static android.system.OsConstants.RT_SCOPE_SITE; 26 import static android.system.OsConstants.RT_SCOPE_UNIVERSE; 27 28 import android.annotation.IntRange; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.annotation.SystemApi; 32 import android.annotation.TestApi; 33 import android.annotation.UnsupportedAppUsage; 34 import android.os.Build; 35 import android.os.Parcel; 36 import android.os.Parcelable; 37 import android.util.Pair; 38 39 import java.net.Inet4Address; 40 import java.net.Inet6Address; 41 import java.net.InetAddress; 42 import java.net.InterfaceAddress; 43 import java.net.UnknownHostException; 44 45 /** 46 * Identifies an IP address on a network link. 47 * 48 * A {@code LinkAddress} consists of: 49 * <ul> 50 * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}). 51 * The address must be unicast, as multicast addresses cannot be assigned to interfaces. 52 * <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties 53 * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}). 54 * <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which 55 * the address is unique (e.g., 56 * {@code android.system.OsConstants.RT_SCOPE_LINK} or 57 * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}). 58 * </ul> 59 */ 60 public class LinkAddress implements Parcelable { 61 /** 62 * IPv4 or IPv6 address. 63 */ 64 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 65 private InetAddress address; 66 67 /** 68 * Prefix length. 69 */ 70 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 71 private int prefixLength; 72 73 /** 74 * Address flags. A bitmask of IFA_F_* values. 75 */ 76 private int flags; 77 78 /** 79 * Address scope. One of the RT_SCOPE_* constants. 80 */ 81 private int scope; 82 83 /** 84 * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and 85 * RFC 6724 section 3.2. 86 * @hide 87 */ 88 private static int scopeForUnicastAddress(InetAddress addr) { 89 if (addr.isAnyLocalAddress()) { 90 return RT_SCOPE_HOST; 91 } 92 93 if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { 94 return RT_SCOPE_LINK; 95 } 96 97 // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2 98 // says that they are assigned global scope. 99 if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) { 100 return RT_SCOPE_SITE; 101 } 102 103 return RT_SCOPE_UNIVERSE; 104 } 105 106 /** 107 * Utility function to check if |address| is a Unique Local IPv6 Unicast Address 108 * (a.k.a. "ULA"; RFC 4193). 109 * 110 * Per RFC 4193 section 8, fc00::/7 identifies these addresses. 111 */ 112 private boolean isIpv6ULA() { 113 if (isIpv6()) { 114 byte[] bytes = address.getAddress(); 115 return ((bytes[0] & (byte)0xfe) == (byte)0xfc); 116 } 117 return false; 118 } 119 120 /** 121 * @return true if the address is IPv6. 122 * @hide 123 */ 124 @TestApi 125 @SystemApi 126 public boolean isIpv6() { 127 return address instanceof Inet6Address; 128 } 129 130 /** 131 * For backward compatibility. 132 * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely 133 * just yet. 134 * @return true if the address is IPv6. 135 * @hide 136 */ 137 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 138 public boolean isIPv6() { 139 return isIpv6(); 140 } 141 142 /** 143 * @return true if the address is IPv4 or is a mapped IPv4 address. 144 * @hide 145 */ 146 @TestApi 147 @SystemApi 148 public boolean isIpv4() { 149 return address instanceof Inet4Address; 150 } 151 152 /** 153 * Utility function for the constructors. 154 */ 155 private void init(InetAddress address, int prefixLength, int flags, int scope) { 156 if (address == null || 157 address.isMulticastAddress() || 158 prefixLength < 0 || 159 (address instanceof Inet4Address && prefixLength > 32) || 160 (prefixLength > 128)) { 161 throw new IllegalArgumentException("Bad LinkAddress params " + address + 162 "/" + prefixLength); 163 } 164 this.address = address; 165 this.prefixLength = prefixLength; 166 this.flags = flags; 167 this.scope = scope; 168 } 169 170 /** 171 * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with 172 * the specified flags and scope. Flags and scope are not checked for validity. 173 * @param address The IP address. 174 * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 175 * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. 176 * @param scope An integer defining the scope in which the address is unique (e.g., 177 * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). 178 * @hide 179 */ 180 @SystemApi 181 @TestApi 182 public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength, 183 int flags, int scope) { 184 init(address, prefixLength, flags, scope); 185 } 186 187 /** 188 * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length. 189 * The flags are set to zero and the scope is determined from the address. 190 * @param address The IP address. 191 * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). 192 * @hide 193 */ 194 @SystemApi 195 @TestApi 196 public LinkAddress(@NonNull InetAddress address, 197 @IntRange(from = 0, to = 128) int prefixLength) { 198 this(address, prefixLength, 0, 0); 199 this.scope = scopeForUnicastAddress(address); 200 } 201 202 /** 203 * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}. 204 * The flags are set to zero and the scope is determined from the address. 205 * @param interfaceAddress The interface address. 206 * @hide 207 */ 208 public LinkAddress(@NonNull InterfaceAddress interfaceAddress) { 209 this(interfaceAddress.getAddress(), 210 interfaceAddress.getNetworkPrefixLength()); 211 } 212 213 /** 214 * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or 215 * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address. 216 * @param address The string to parse. 217 * @hide 218 */ 219 @SystemApi 220 @TestApi 221 public LinkAddress(@NonNull String address) { 222 this(address, 0, 0); 223 this.scope = scopeForUnicastAddress(this.address); 224 } 225 226 /** 227 * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or 228 * "2001:db8::1/64", with the specified flags and scope. 229 * @param address The string to parse. 230 * @param flags The address flags. 231 * @param scope The address scope. 232 * @hide 233 */ 234 @SystemApi 235 @TestApi 236 public LinkAddress(@NonNull String address, int flags, int scope) { 237 // This may throw an IllegalArgumentException; catching it is the caller's responsibility. 238 // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24". 239 Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address); 240 init(ipAndMask.first, ipAndMask.second, flags, scope); 241 } 242 243 /** 244 * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64". 245 * The string representation does not contain the flags and scope, just the address and prefix 246 * length. 247 */ 248 @Override 249 public String toString() { 250 return address.getHostAddress() + "/" + prefixLength; 251 } 252 253 /** 254 * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if 255 * their address, prefix length, flags and scope are equal. Thus, for example, two addresses 256 * that have the same address and prefix length are not equal if one of them is deprecated and 257 * the other is not. 258 * 259 * @param obj the object to be tested for equality. 260 * @return {@code true} if both objects are equal, {@code false} otherwise. 261 */ 262 @Override 263 public boolean equals(Object obj) { 264 if (!(obj instanceof LinkAddress)) { 265 return false; 266 } 267 LinkAddress linkAddress = (LinkAddress) obj; 268 return this.address.equals(linkAddress.address) && 269 this.prefixLength == linkAddress.prefixLength && 270 this.flags == linkAddress.flags && 271 this.scope == linkAddress.scope; 272 } 273 274 /** 275 * Returns a hashcode for this address. 276 */ 277 @Override 278 public int hashCode() { 279 return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope; 280 } 281 282 /** 283 * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} 284 * represent the same address. Two {@code LinkAddresses} represent the same address 285 * if they have the same IP address and prefix length, even if their properties are 286 * different. 287 * 288 * @param other the {@code LinkAddress} to compare to. 289 * @return {@code true} if both objects have the same address and prefix length, {@code false} 290 * otherwise. 291 * @hide 292 */ 293 @TestApi 294 @SystemApi 295 public boolean isSameAddressAs(@Nullable LinkAddress other) { 296 if (other == null) { 297 return false; 298 } 299 return address.equals(other.address) && prefixLength == other.prefixLength; 300 } 301 302 /** 303 * Returns the {@link InetAddress} of this {@code LinkAddress}. 304 */ 305 public InetAddress getAddress() { 306 return address; 307 } 308 309 /** 310 * Returns the prefix length of this {@code LinkAddress}. 311 */ 312 @IntRange(from = 0, to = 128) 313 public int getPrefixLength() { 314 return prefixLength; 315 } 316 317 /** 318 * Returns the prefix length of this {@code LinkAddress}. 319 * TODO: Delete all callers and remove in favour of getPrefixLength(). 320 * @hide 321 */ 322 @UnsupportedAppUsage 323 @IntRange(from = 0, to = 128) 324 public int getNetworkPrefixLength() { 325 return getPrefixLength(); 326 } 327 328 /** 329 * Returns the flags of this {@code LinkAddress}. 330 */ 331 public int getFlags() { 332 return flags; 333 } 334 335 /** 336 * Returns the scope of this {@code LinkAddress}. 337 */ 338 public int getScope() { 339 return scope; 340 } 341 342 /** 343 * Returns true if this {@code LinkAddress} is global scope and preferred. 344 * @hide 345 */ 346 @TestApi 347 @SystemApi 348 public boolean isGlobalPreferred() { 349 /** 350 * Note that addresses flagged as IFA_F_OPTIMISTIC are 351 * simultaneously flagged as IFA_F_TENTATIVE (when the tentative 352 * state has cleared either DAD has succeeded or failed, and both 353 * flags are cleared regardless). 354 */ 355 return (scope == RT_SCOPE_UNIVERSE 356 && !isIpv6ULA() 357 && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L 358 && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L)); 359 } 360 361 /** 362 * Implement the Parcelable interface. 363 */ 364 public int describeContents() { 365 return 0; 366 } 367 368 /** 369 * Implement the Parcelable interface. 370 */ 371 public void writeToParcel(Parcel dest, int flags) { 372 dest.writeByteArray(address.getAddress()); 373 dest.writeInt(prefixLength); 374 dest.writeInt(this.flags); 375 dest.writeInt(scope); 376 } 377 378 /** 379 * Implement the Parcelable interface. 380 */ 381 public static final @android.annotation.NonNull Creator<LinkAddress> CREATOR = 382 new Creator<LinkAddress>() { 383 public LinkAddress createFromParcel(Parcel in) { 384 InetAddress address = null; 385 try { 386 address = InetAddress.getByAddress(in.createByteArray()); 387 } catch (UnknownHostException e) { 388 // Nothing we can do here. When we call the constructor, we'll throw an 389 // IllegalArgumentException, because a LinkAddress can't have a null 390 // InetAddress. 391 } 392 int prefixLength = in.readInt(); 393 int flags = in.readInt(); 394 int scope = in.readInt(); 395 return new LinkAddress(address, prefixLength, flags, scope); 396 } 397 398 public LinkAddress[] newArray(int size) { 399 return new LinkAddress[size]; 400 } 401 }; 402 } 403