/* * Copyright (C) 2011 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.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import com.android.net.module.util.NetUtils; import com.android.net.module.util.NetworkStackConstants; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Collection; import java.util.Objects; /** * Represents a network route. *
* This is used both to describe static network configuration and live network * configuration information. * * A route contains three pieces of information: *
0.0.0.0
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
* route ::/0
if gateway is an instance of
* {@link Inet6Address}.
*
* destination and gateway may not both be null.
*
* @param destination the destination prefix
* @param gateway the IP address to route packets through
* @param iface the interface name to send packets on
* @param type the type of this route
*
* @hide
*/
@SystemApi
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
@Nullable String iface, @RouteType int type) {
this(destination, gateway, iface, type, 0);
}
/**
* Constructs a RouteInfo object.
*
* If destination is null, then gateway must be specified and the
* constructed route is either the IPv4 default route 0.0.0.0
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
* route ::/0
if gateway is an instance of
* {@link Inet6Address}.
*
* destination and gateway may not both be null.
*
* @param destination the destination prefix
* @param gateway the IP address to route packets through
* @param iface the interface name to send packets on
* @param type the type of this route
* @param mtu the maximum transmission unit size for this route
*
* @hide
*/
@SystemApi
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
@Nullable String iface, @RouteType int type, int mtu) {
switch (type) {
case RTN_UNICAST:
case RTN_UNREACHABLE:
case RTN_THROW:
// TODO: It would be nice to ensure that route types that don't have nexthops or
// interfaces, such as unreachable or throw, can't be created if an interface or
// a gateway is specified. This is a bit too complicated to do at the moment
// because:
//
// - LinkProperties sets the interface on routes added to it, and modifies the
// interfaces of all the routes when its interface name changes.
// - Even when the gateway is null, we store a non-null gateway here.
//
// For now, we just rely on the code that sets routes to do things properly.
break;
default:
throw new IllegalArgumentException("Unknown route type " + type);
}
if (destination == null) {
if (gateway != null) {
if (gateway instanceof Inet4Address) {
destination = new IpPrefix(NetworkStackConstants.IPV4_ADDR_ANY, 0);
} else {
destination = new IpPrefix(NetworkStackConstants.IPV6_ADDR_ANY, 0);
}
} else {
// no destination, no gateway. invalid.
throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
destination);
}
}
// TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
// matches the documented behaviour. Before we can do this we need to fix all callers (e.g.,
// ConnectivityService) to stop doing things like r.getGateway().equals(), ... .
if (gateway == null) {
if (destination.getAddress() instanceof Inet4Address) {
gateway = NetworkStackConstants.IPV4_ADDR_ANY;
} else {
gateway = NetworkStackConstants.IPV6_ADDR_ANY;
}
}
mHasGateway = (!gateway.isAnyLocalAddress());
if ((destination.getAddress() instanceof Inet4Address
&& !(gateway instanceof Inet4Address))
|| (destination.getAddress() instanceof Inet6Address
&& !(gateway instanceof Inet6Address))) {
throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
}
mDestination = destination; // IpPrefix objects are immutable.
mGateway = gateway; // InetAddress objects are immutable.
mInterface = iface; // Strings are immutable.
mType = type;
mIsHost = isHost();
mMtu = mtu;
}
/**
* Constructs a {@code RouteInfo} object.
*
* If destination is null, then gateway must be specified and the
* constructed route is either the IPv4 default route 0.0.0.0
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
* route ::/0
if gateway is an instance of {@link Inet6Address}.
*
* Destination and gateway may not both be null.
*
* @param destination the destination address and prefix in an {@link IpPrefix}
* @param gateway the {@link InetAddress} to route packets through
* @param iface the interface name to send packets on
*
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
@Nullable String iface) {
this(destination, gateway, iface, RTN_UNICAST);
}
/**
* @hide
*/
@UnsupportedAppUsage
public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
@Nullable String iface) {
this(destination == null ? null :
new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
gateway, iface);
}
/**
* Constructs a {@code RouteInfo} object.
*
* If destination is null, then gateway must be specified and the
* constructed route is either the IPv4 default route 0.0.0.0
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
* route ::/0
if gateway is an instance of {@link Inet6Address}.
*
* Destination and gateway may not both be null.
*
* @param destination the destination address and prefix in an {@link IpPrefix}
* @param gateway the {@link InetAddress} to route packets through
*
* @hide
*/
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
this(destination, gateway, null);
}
/**
* @hide
*
* TODO: Remove this.
*/
@UnsupportedAppUsage
public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
this(destination, gateway, null);
}
/**
* Constructs a default {@code RouteInfo} object.
*
* @param gateway the {@link InetAddress} to route packets through
*
* @hide
*/
@UnsupportedAppUsage
public RouteInfo(@NonNull InetAddress gateway) {
this((IpPrefix) null, gateway, null);
}
/**
* Constructs a {@code RouteInfo} object representing a direct connected subnet.
*
* @param destination the {@link IpPrefix} describing the address and prefix
* length of the subnet.
*
* @hide
*/
public RouteInfo(@NonNull IpPrefix destination) {
this(destination, null, null);
}
/**
* @hide
*/
public RouteInfo(@NonNull LinkAddress destination) {
this(destination, null, null);
}
/**
* @hide
*/
public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
this(destination, null, null, type);
}
/**
* @hide
*/
public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
return makeHostRoute(host, null, iface);
}
/**
* @hide
*/
public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
@Nullable String iface) {
if (host == null) return null;
if (host instanceof Inet4Address) {
return new RouteInfo(new IpPrefix(host, 32), gateway, iface);
} else {
return new RouteInfo(new IpPrefix(host, 128), gateway, iface);
}
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean isHost() {
return (mDestination.getAddress() instanceof Inet4Address &&
mDestination.getPrefixLength() == 32) ||
(mDestination.getAddress() instanceof Inet6Address &&
mDestination.getPrefixLength() == 128);
}
/**
* Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
*
* @return {@link IpPrefix} specifying the destination. This is never {@code null}.
*/
@NonNull
public IpPrefix getDestination() {
return mDestination;
}
/**
* TODO: Convert callers to use IpPrefix and then remove.
* @hide
*/
@NonNull
public LinkAddress getDestinationLinkAddress() {
return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
}
/**
* Retrieves the gateway or next hop {@link InetAddress} for this route.
*
* @return {@link InetAddress} specifying the gateway or next hop. This may be
* {@code null} for a directly-connected route."
*/
@Nullable
public InetAddress getGateway() {
return mGateway;
}
/**
* Retrieves the interface used for this route if specified, else {@code null}.
*
* @return The name of the interface used for this route.
*/
@Nullable
public String getInterface() {
return mInterface;
}
/**
* Retrieves the type of this route.
*
* @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
*/
@RouteType
public int getType() {
return mType;
}
/**
* Retrieves the MTU size for this route.
*
* @return The MTU size, or 0 if it has not been set.
* @hide
*/
@SystemApi
public int getMtu() {
return mMtu;
}
/**
* Indicates if this route is a default route (ie, has no destination specified).
*
* @return {@code true} if the destination has a prefix length of 0.
*/
public boolean isDefaultRoute() {
return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
}
/**
* Indicates if this route is an unreachable default route.
*
* @return {@code true} if it's an unreachable route with prefix length of 0.
* @hide
*/
private boolean isUnreachableDefaultRoute() {
return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0;
}
/**
* Indicates if this route is an IPv4 default route.
* @hide
*/
public boolean isIPv4Default() {
return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
}
/**
* Indicates if this route is an IPv4 unreachable default route.
* @hide
*/
public boolean isIPv4UnreachableDefault() {
return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
}
/**
* Indicates if this route is an IPv6 default route.
* @hide
*/
public boolean isIPv6Default() {
return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
}
/**
* Indicates if this route is an IPv6 unreachable default route.
* @hide
*/
public boolean isIPv6UnreachableDefault() {
return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
}
/**
* Indicates if this route is a host route (ie, matches only a single host address).
*
* @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
* respectively.
* @hide
*/
public boolean isHostRoute() {
return mIsHost;
}
/**
* Indicates if this route has a next hop ({@code true}) or is directly-connected
* ({@code false}).
*
* @return {@code true} if a gateway is specified
*/
public boolean hasGateway() {
return mHasGateway;
}
/**
* Determines whether the destination and prefix of this route includes the specified
* address.
*
* @param destination A {@link InetAddress} to test to see if it would match this route.
* @return {@code true} if the destination and prefix length cover the given address.
*/
public boolean matches(InetAddress destination) {
return mDestination.contains(destination);
}
/**
* Find the route from a Collection of routes that best matches a given address.
* May return null if no routes are applicable.
* @param routes a Collection of RouteInfos to chose from
* @param dest the InetAddress your trying to get to
* @return the RouteInfo from the Collection that best fits the given address
*
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Nullable
public static RouteInfo selectBestRoute(CollectionRouteInfo
object.
*/
public int hashCode() {
return (mDestination.hashCode() * 41)
+ (mGateway == null ? 0 :mGateway.hashCode() * 47)
+ (mInterface == null ? 0 :mInterface.hashCode() * 67)
+ (mType * 71) + (mMtu * 89);
}
/**
* Implement the Parcelable interface
*/
public int describeContents() {
return 0;
}
/**
* Implement the Parcelable interface
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mDestination, flags);
byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
dest.writeByteArray(gatewayBytes);
dest.writeString(mInterface);
dest.writeInt(mType);
dest.writeInt(mMtu);
}
/**
* Implement the Parcelable interface.
*/
public static final @android.annotation.NonNull Creator