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