2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 import android.os.Parcel;
20 import android.os.Parcelable;
22 import java.net.UnknownHostException;
23 import java.net.InetAddress;
24 import java.net.Inet4Address;
25 import java.net.Inet6Address;
27 import java.util.Collection;
28 import java.util.Objects;
31 * Represents a network route.
33 * This is used both to describe static network configuration and live network
34 * configuration information.
36 * A route contains three pieces of information:
38 * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
39 * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
40 * implied by the gateway IP address.
41 * <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it
42 * indicates a directly-connected route.
43 * <li>an interface (which may be unspecified).
45 * Either the destination or the gateway may be {@code null}, but not both. If the
46 * destination and gateway are both specified, they must be of the same address family
49 public final class RouteInfo implements Parcelable {
51 * The IP destination address for this route.
53 private final IpPrefix mDestination;
56 * The gateway address for this route.
58 private final InetAddress mGateway;
61 * The interface for this route.
63 private final String mInterface;
66 /** Unicast route. @hide */
67 public static final int RTN_UNICAST = 1;
69 /** Unreachable route. @hide */
70 public static final int RTN_UNREACHABLE = 7;
72 /** Throw route. @hide */
73 public static final int RTN_THROW = 9;
76 * The type of this route; one of the RTN_xxx constants above.
78 private final int mType;
80 // Derived data members.
81 // TODO: remove these.
82 private final boolean mIsHost;
83 private final boolean mHasGateway;
86 * Constructs a RouteInfo object.
88 * If destination is null, then gateway must be specified and the
89 * constructed route is either the IPv4 default route <code>0.0.0.0</code>
90 * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
91 * route <code>::/0</code> if gateway is an instance of
92 * {@link Inet6Address}.
94 * destination and gateway may not both be null.
96 * @param destination the destination prefix
97 * @param gateway the IP address to route packets through
98 * @param iface the interface name to send packets on
102 public RouteInfo(IpPrefix destination, InetAddress gateway, String iface, int type) {
105 case RTN_UNREACHABLE:
107 // TODO: It would be nice to ensure that route types that don't have nexthops or
108 // interfaces, such as unreachable or throw, can't be created if an interface or
109 // a gateway is specified. This is a bit too complicated to do at the moment
112 // - LinkProperties sets the interface on routes added to it, and modifies the
113 // interfaces of all the routes when its interface name changes.
114 // - Even when the gateway is null, we store a non-null gateway here.
116 // For now, we just rely on the code that sets routes to do things properly.
119 throw new IllegalArgumentException("Unknown route type " + type);
122 if (destination == null) {
123 if (gateway != null) {
124 if (gateway instanceof Inet4Address) {
125 destination = new IpPrefix(Inet4Address.ANY, 0);
127 destination = new IpPrefix(Inet6Address.ANY, 0);
130 // no destination, no gateway. invalid.
131 throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
135 // TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
136 // matches the documented behaviour. Before we can do this we need to fix all callers (e.g.,
137 // ConnectivityService) to stop doing things like r.getGateway().equals(), ... .
138 if (gateway == null) {
139 if (destination.getAddress() instanceof Inet4Address) {
140 gateway = Inet4Address.ANY;
142 gateway = Inet6Address.ANY;
145 mHasGateway = (!gateway.isAnyLocalAddress());
147 if ((destination.getAddress() instanceof Inet4Address &&
148 (gateway instanceof Inet4Address == false)) ||
149 (destination.getAddress() instanceof Inet6Address &&
150 (gateway instanceof Inet6Address == false))) {
151 throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
153 mDestination = destination; // IpPrefix objects are immutable.
154 mGateway = gateway; // InetAddress objects are immutable.
155 mInterface = iface; // Strings are immutable.
163 public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
164 this(destination, gateway, iface, RTN_UNICAST);
170 public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
171 this(destination == null ? null :
172 new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
177 * Constructs a {@code RouteInfo} object.
179 * If destination is null, then gateway must be specified and the
180 * constructed route is either the IPv4 default route <code>0.0.0.0</code>
181 * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
182 * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
184 * Destination and gateway may not both be null.
186 * @param destination the destination address and prefix in an {@link IpPrefix}
187 * @param gateway the {@link InetAddress} to route packets through
191 public RouteInfo(IpPrefix destination, InetAddress gateway) {
192 this(destination, gateway, null);
200 public RouteInfo(LinkAddress destination, InetAddress gateway) {
201 this(destination, gateway, null);
205 * Constructs a default {@code RouteInfo} object.
207 * @param gateway the {@link InetAddress} to route packets through
211 public RouteInfo(InetAddress gateway) {
212 this((IpPrefix) null, gateway, null);
216 * Constructs a {@code RouteInfo} object representing a direct connected subnet.
218 * @param destination the {@link IpPrefix} describing the address and prefix
219 * length of the subnet.
223 public RouteInfo(IpPrefix destination) {
224 this(destination, null, null);
230 public RouteInfo(LinkAddress destination) {
231 this(destination, null, null);
237 public RouteInfo(IpPrefix destination, int type) {
238 this(destination, null, null, type);
244 public static RouteInfo makeHostRoute(InetAddress host, String iface) {
245 return makeHostRoute(host, null, iface);
251 public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
252 if (host == null) return null;
254 if (host instanceof Inet4Address) {
255 return new RouteInfo(new IpPrefix(host, 32), gateway, iface);
257 return new RouteInfo(new IpPrefix(host, 128), gateway, iface);
261 private boolean isHost() {
262 return (mDestination.getAddress() instanceof Inet4Address &&
263 mDestination.getPrefixLength() == 32) ||
264 (mDestination.getAddress() instanceof Inet6Address &&
265 mDestination.getPrefixLength() == 128);
269 * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
271 * @return {@link IpPrefix} specifying the destination. This is never {@code null}.
273 public IpPrefix getDestination() {
278 * TODO: Convert callers to use IpPrefix and then remove.
281 public LinkAddress getDestinationLinkAddress() {
282 return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
286 * Retrieves the gateway or next hop {@link InetAddress} for this route.
288 * @return {@link InetAddress} specifying the gateway or next hop. This may be
289 * {@code null} for a directly-connected route."
291 public InetAddress getGateway() {
296 * Retrieves the interface used for this route if specified, else {@code null}.
298 * @return The name of the interface used for this route.
300 public String getInterface() {
305 * Retrieves the type of this route.
307 * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
311 public int getType() {
316 * Indicates if this route is a default route (ie, has no destination specified).
318 * @return {@code true} if the destination has a prefix length of 0.
320 public boolean isDefaultRoute() {
321 return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
325 * Indicates if this route is an IPv4 default route.
328 public boolean isIPv4Default() {
329 return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
333 * Indicates if this route is an IPv6 default route.
336 public boolean isIPv6Default() {
337 return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
341 * Indicates if this route is a host route (ie, matches only a single host address).
343 * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
347 public boolean isHostRoute() {
352 * Indicates if this route has a next hop ({@code true}) or is directly-connected
355 * @return {@code true} if a gateway is specified
358 public boolean hasGateway() {
363 * Determines whether the destination and prefix of this route includes the specified
366 * @param destination A {@link InetAddress} to test to see if it would match this route.
367 * @return {@code true} if the destination and prefix length cover the given address.
369 public boolean matches(InetAddress destination) {
370 return mDestination.contains(destination);
374 * Find the route from a Collection of routes that best matches a given address.
375 * May return null if no routes are applicable.
376 * @param routes a Collection of RouteInfos to chose from
377 * @param dest the InetAddress your trying to get to
378 * @return the RouteInfo from the Collection that best fits the given address
382 public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
383 if ((routes == null) || (dest == null)) return null;
385 RouteInfo bestRoute = null;
386 // pick a longest prefix match under same address type
387 for (RouteInfo route : routes) {
388 if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
389 if ((bestRoute != null) &&
390 (bestRoute.mDestination.getPrefixLength() >=
391 route.mDestination.getPrefixLength())) {
394 if (route.matches(dest)) bestRoute = route;
401 * Returns a human-readable description of this object.
403 public String toString() {
405 if (mDestination != null) val = mDestination.toString();
406 if (mType == RTN_UNREACHABLE) {
407 val += " unreachable";
408 } else if (mType == RTN_THROW) {
412 if (mGateway != null) val += " " + mGateway.getHostAddress();
413 if (mInterface != null) val += " " + mInterface;
414 if (mType != RTN_UNICAST) {
415 val += " unknown type " + mType;
422 * Compares this RouteInfo object against the specified object and indicates if they are equal.
423 * @return {@code true} if the objects are equal, {@code false} otherwise.
425 public boolean equals(Object obj) {
426 if (this == obj) return true;
428 if (!(obj instanceof RouteInfo)) return false;
430 RouteInfo target = (RouteInfo) obj;
432 return Objects.equals(mDestination, target.getDestination()) &&
433 Objects.equals(mGateway, target.getGateway()) &&
434 Objects.equals(mInterface, target.getInterface()) &&
435 mType == target.getType();
439 * Returns a hashcode for this <code>RouteInfo</code> object.
441 public int hashCode() {
442 return (mDestination.hashCode() * 41)
443 + (mGateway == null ? 0 :mGateway.hashCode() * 47)
444 + (mInterface == null ? 0 :mInterface.hashCode() * 67)
449 * Implement the Parcelable interface
451 public int describeContents() {
456 * Implement the Parcelable interface
458 public void writeToParcel(Parcel dest, int flags) {
459 dest.writeParcelable(mDestination, flags);
460 byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
461 dest.writeByteArray(gatewayBytes);
462 dest.writeString(mInterface);
463 dest.writeInt(mType);
467 * Implement the Parcelable interface.
469 public static final Creator<RouteInfo> CREATOR =
470 new Creator<RouteInfo>() {
471 public RouteInfo createFromParcel(Parcel in) {
472 IpPrefix dest = in.readParcelable(null);
474 InetAddress gateway = null;
475 byte[] addr = in.createByteArray();
477 gateway = InetAddress.getByAddress(addr);
478 } catch (UnknownHostException e) {}
480 String iface = in.readString();
481 int type = in.readInt();
483 return new RouteInfo(dest, gateway, iface, type);
486 public RouteInfo[] newArray(int size) {
487 return new RouteInfo[size];