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