/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net; import android.os.Parcel; import android.os.Parcelable; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.UnknownHostException; import static libcore.io.OsConstants.IFA_F_DADFAILED; import static libcore.io.OsConstants.IFA_F_DEPRECATED; import static libcore.io.OsConstants.IFA_F_TENTATIVE; import static libcore.io.OsConstants.RT_SCOPE_HOST; import static libcore.io.OsConstants.RT_SCOPE_LINK; import static libcore.io.OsConstants.RT_SCOPE_SITE; import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE; /** * Identifies an IP address on a network link. * * A {@code LinkAddress} consists of: *
* When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
* scope are optional. If they are not specified, the flags are set to zero, and the scope will be
* determined based on the IP address (e.g., link-local addresses will be created with a scope of
* {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are
* specified, they are not checked for validity.
*
* @hide
*/
public class LinkAddress implements Parcelable {
/**
* IPv4 or IPv6 address.
*/
private InetAddress address;
/**
* Prefix length.
*/
private int prefixLength;
/**
* Address flags. A bitmask of IFA_F_* values.
*/
private int flags;
/**
* Address scope. One of the RT_SCOPE_* constants.
*/
private int scope;
/**
* Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
* RFC 6724 section 3.2.
* @hide
*/
static int scopeForUnicastAddress(InetAddress addr) {
if (addr.isAnyLocalAddress()) {
return RT_SCOPE_HOST;
}
if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
return RT_SCOPE_LINK;
}
// isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
// says that they are assigned global scope.
if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
return RT_SCOPE_SITE;
}
return RT_SCOPE_UNIVERSE;
}
/**
* Utility function for the constructors.
*/
private void init(InetAddress address, int prefixLength, int flags, int scope) {
if (address == null ||
address.isMulticastAddress() ||
prefixLength < 0 ||
((address instanceof Inet4Address) && prefixLength > 32) ||
(prefixLength > 128)) {
throw new IllegalArgumentException("Bad LinkAddress params " + address +
"/" + prefixLength);
}
this.address = address;
this.prefixLength = prefixLength;
this.flags = flags;
this.scope = scope;
}
/**
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
* the specified flags and scope. Flags and scope are not checked for validity.
* @param address The IP address.
* @param prefixLength The prefix length.
*/
public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
init(address, prefixLength, flags, scope);
}
/**
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
* The flags are set to zero and the scope is determined from the address.
* @param address The IP address.
* @param prefixLength The prefix length.
*/
public LinkAddress(InetAddress address, int prefixLength) {
this(address, prefixLength, 0, 0);
this.scope = scopeForUnicastAddress(address);
}
/**
* Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
* The flags are set to zero and the scope is determined from the address.
* @param interfaceAddress The interface address.
*/
public LinkAddress(InterfaceAddress interfaceAddress) {
this(interfaceAddress.getAddress(),
interfaceAddress.getNetworkPrefixLength());
}
/**
* Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
* "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
* @param string The string to parse.
*/
public LinkAddress(String address) {
this(address, 0, 0);
this.scope = scopeForUnicastAddress(this.address);
}
/**
* Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
* "2001:db8::1/64", with the specified flags and scope.
* @param string The string to parse.
* @param flags The address flags.
* @param scope The address scope.
*/
public LinkAddress(String address, int flags, int scope) {
InetAddress inetAddress = null;
int prefixLength = -1;
try {
String [] pieces = address.split("/", 2);
prefixLength = Integer.parseInt(pieces[1]);
inetAddress = InetAddress.parseNumericAddress(pieces[0]);
} catch (NullPointerException e) { // Null string.
} catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
} catch (NumberFormatException e) { // Non-numeric prefix.
} catch (IllegalArgumentException e) { // Invalid IP address.
}
if (inetAddress == null || prefixLength == -1) {
throw new IllegalArgumentException("Bad LinkAddress params " + address);
}
init(inetAddress, prefixLength, flags, scope);
}
/**
* Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
* The string representation does not contain the flags and scope, just the address and prefix
* length.
*/
@Override
public String toString() {
return address.getHostAddress() + "/" + prefixLength;
}
/**
* Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
* their address, prefix length, flags and scope are equal.
*
* @param obj the object to be tested for equality.
* @return {@code true} if both objects are equal, {@code false} otherwise.
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof LinkAddress)) {
return false;
}
LinkAddress linkAddress = (LinkAddress) obj;
return this.address.equals(linkAddress.address) &&
this.prefixLength == linkAddress.prefixLength &&
this.flags == linkAddress.flags &&
this.scope == linkAddress.scope;
}
/**
* Returns a hashcode for this address.
*/
@Override
public int hashCode() {
return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
}
/**
* Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent
* the same address. Two LinkAddresses represent the same address if they have the same IP
* address and prefix length, even if their properties are different.
*
* @param other the {@code LinkAddress} to compare to.
* @return {@code true} if both objects have the same address and prefix length, {@code false}
* otherwise.
*/
public boolean isSameAddressAs(LinkAddress other) {
return address.equals(other.address) && prefixLength == other.prefixLength;
}
/**
* Returns the InetAddress of this address.
*/
public InetAddress getAddress() {
return address;
}
/**
* Returns the prefix length of this address.
*/
public int getNetworkPrefixLength() {
return prefixLength;
}
/**
* Returns the flags of this address.
*/
public int getFlags() {
return flags;
}
/**
* Returns the scope of this address.
*/
public int getScope() {
return scope;
}
/**
* Returns true if this {@code LinkAddress} is global scope and preferred.
*/
public boolean isGlobalPreferred() {
return (scope == RT_SCOPE_UNIVERSE &&
(flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L);
}
/**
* Implement the Parcelable interface.
* @hide
*/
public int describeContents() {
return 0;
}
/**
* Implement the Parcelable interface.
* @hide
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeByteArray(address.getAddress());
dest.writeInt(prefixLength);
dest.writeInt(this.flags);
dest.writeInt(scope);
}
/**
* Implement the Parcelable interface.
* @hide
*/
public static final Creator