• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.annotation.TestApi;
24 import android.annotation.UnsupportedAppUsage;
25 import android.os.Build;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.net.Inet4Address;
32 import java.net.Inet6Address;
33 import java.net.InetAddress;
34 import java.net.UnknownHostException;
35 import java.util.Collection;
36 import java.util.Objects;
37 
38 /**
39  * Represents a network route.
40  * <p>
41  * This is used both to describe static network configuration and live network
42  * configuration information.
43  *
44  * A route contains three pieces of information:
45  * <ul>
46  * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
47  *     If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
48  *     implied by the gateway IP address.
49  * <li>a gateway {@link InetAddress} indicating the next hop to use.  If this is {@code null} it
50  *     indicates a directly-connected route.
51  * <li>an interface (which may be unspecified).
52  * </ul>
53  * Either the destination or the gateway may be {@code null}, but not both.  If the
54  * destination and gateway are both specified, they must be of the same address family
55  * (IPv4 or IPv6).
56  */
57 public final class RouteInfo implements Parcelable {
58     /** @hide */
59     @IntDef(value = {
60             RTN_UNICAST,
61             RTN_UNREACHABLE,
62             RTN_THROW,
63     })
64     @Retention(RetentionPolicy.SOURCE)
65     public @interface RouteType {}
66 
67     /**
68      * The IP destination address for this route.
69      */
70     @NonNull
71     private final IpPrefix mDestination;
72 
73     /**
74      * The gateway address for this route.
75      */
76     @UnsupportedAppUsage
77     @Nullable
78     private final InetAddress mGateway;
79 
80     /**
81      * The interface for this route.
82      */
83     @Nullable
84     private final String mInterface;
85 
86 
87     /** Unicast route. @hide */
88     @SystemApi
89     @TestApi
90     public static final int RTN_UNICAST = 1;
91 
92     /** Unreachable route. @hide */
93     @SystemApi
94     @TestApi
95     public static final int RTN_UNREACHABLE = 7;
96 
97     /** Throw route. @hide */
98     @SystemApi
99     @TestApi
100     public static final int RTN_THROW = 9;
101 
102     /**
103      * The type of this route; one of the RTN_xxx constants above.
104      */
105     private final int mType;
106 
107     // Derived data members.
108     // TODO: remove these.
109     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
110     private final boolean mIsHost;
111     private final boolean mHasGateway;
112 
113     /**
114      * Constructs a RouteInfo object.
115      *
116      * If destination is null, then gateway must be specified and the
117      * constructed route is either the IPv4 default route <code>0.0.0.0</code>
118      * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
119      * route <code>::/0</code> if gateway is an instance of
120      * {@link Inet6Address}.
121      * <p>
122      * destination and gateway may not both be null.
123      *
124      * @param destination the destination prefix
125      * @param gateway the IP address to route packets through
126      * @param iface the interface name to send packets on
127      * @param type the type of this route
128      *
129      * @hide
130      */
131     @SystemApi
132     @TestApi
RouteInfo(@ullable IpPrefix destination, @Nullable InetAddress gateway, @Nullable String iface, @RouteType int type)133     public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
134             @Nullable String iface, @RouteType int type) {
135         switch (type) {
136             case RTN_UNICAST:
137             case RTN_UNREACHABLE:
138             case RTN_THROW:
139                 // TODO: It would be nice to ensure that route types that don't have nexthops or
140                 // interfaces, such as unreachable or throw, can't be created if an interface or
141                 // a gateway is specified. This is a bit too complicated to do at the moment
142                 // because:
143                 //
144                 // - LinkProperties sets the interface on routes added to it, and modifies the
145                 //   interfaces of all the routes when its interface name changes.
146                 // - Even when the gateway is null, we store a non-null gateway here.
147                 //
148                 // For now, we just rely on the code that sets routes to do things properly.
149                 break;
150             default:
151                 throw new IllegalArgumentException("Unknown route type " + type);
152         }
153 
154         if (destination == null) {
155             if (gateway != null) {
156                 if (gateway instanceof Inet4Address) {
157                     destination = new IpPrefix(Inet4Address.ANY, 0);
158                 } else {
159                     destination = new IpPrefix(Inet6Address.ANY, 0);
160                 }
161             } else {
162                 // no destination, no gateway. invalid.
163                 throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
164                                                    destination);
165             }
166         }
167         // TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
168         // matches the documented behaviour. Before we can do this we need to fix all callers (e.g.,
169         // ConnectivityService) to stop doing things like r.getGateway().equals(), ... .
170         if (gateway == null) {
171             if (destination.getAddress() instanceof Inet4Address) {
172                 gateway = Inet4Address.ANY;
173             } else {
174                 gateway = Inet6Address.ANY;
175             }
176         }
177         mHasGateway = (!gateway.isAnyLocalAddress());
178 
179         if ((destination.getAddress() instanceof Inet4Address &&
180                  (gateway instanceof Inet4Address == false)) ||
181                 (destination.getAddress() instanceof Inet6Address &&
182                  (gateway instanceof Inet6Address == false))) {
183             throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
184         }
185         mDestination = destination;  // IpPrefix objects are immutable.
186         mGateway = gateway;          // InetAddress objects are immutable.
187         mInterface = iface;          // Strings are immutable.
188         mType = type;
189         mIsHost = isHost();
190     }
191 
192     /**
193      * Constructs a {@code RouteInfo} object.
194      *
195      * If destination is null, then gateway must be specified and the
196      * constructed route is either the IPv4 default route <code>0.0.0.0</code>
197      * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
198      * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
199      * <p>
200      * Destination and gateway may not both be null.
201      *
202      * @param destination the destination address and prefix in an {@link IpPrefix}
203      * @param gateway the {@link InetAddress} to route packets through
204      * @param iface the interface name to send packets on
205      *
206      * @hide
207      */
208     @UnsupportedAppUsage
RouteInfo(@ullable IpPrefix destination, @Nullable InetAddress gateway, @Nullable String iface)209     public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
210             @Nullable String iface) {
211         this(destination, gateway, iface, RTN_UNICAST);
212     }
213 
214     /**
215      * @hide
216      */
217     @UnsupportedAppUsage
RouteInfo(@ullable LinkAddress destination, @Nullable InetAddress gateway, @Nullable String iface)218     public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
219             @Nullable String iface) {
220         this(destination == null ? null :
221                 new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
222                 gateway, iface);
223     }
224 
225     /**
226      * Constructs a {@code RouteInfo} object.
227      *
228      * If destination is null, then gateway must be specified and the
229      * constructed route is either the IPv4 default route <code>0.0.0.0</code>
230      * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
231      * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
232      * <p>
233      * Destination and gateway may not both be null.
234      *
235      * @param destination the destination address and prefix in an {@link IpPrefix}
236      * @param gateway the {@link InetAddress} to route packets through
237      *
238      * @hide
239      */
RouteInfo(@ullable IpPrefix destination, @Nullable InetAddress gateway)240     public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
241         this(destination, gateway, null);
242     }
243 
244     /**
245      * @hide
246      *
247      * TODO: Remove this.
248      */
249     @UnsupportedAppUsage
RouteInfo(@ullable LinkAddress destination, @Nullable InetAddress gateway)250     public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
251         this(destination, gateway, null);
252     }
253 
254     /**
255      * Constructs a default {@code RouteInfo} object.
256      *
257      * @param gateway the {@link InetAddress} to route packets through
258      *
259      * @hide
260      */
261     @UnsupportedAppUsage
RouteInfo(@onNull InetAddress gateway)262     public RouteInfo(@NonNull InetAddress gateway) {
263         this((IpPrefix) null, gateway, null);
264     }
265 
266     /**
267      * Constructs a {@code RouteInfo} object representing a direct connected subnet.
268      *
269      * @param destination the {@link IpPrefix} describing the address and prefix
270      *                    length of the subnet.
271      *
272      * @hide
273      */
RouteInfo(@onNull IpPrefix destination)274     public RouteInfo(@NonNull IpPrefix destination) {
275         this(destination, null, null);
276     }
277 
278     /**
279      * @hide
280      */
RouteInfo(@onNull LinkAddress destination)281     public RouteInfo(@NonNull LinkAddress destination) {
282         this(destination, null, null);
283     }
284 
285     /**
286      * @hide
287      */
RouteInfo(@onNull IpPrefix destination, @RouteType int type)288     public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
289         this(destination, null, null, type);
290     }
291 
292     /**
293      * @hide
294      */
makeHostRoute(@onNull InetAddress host, @Nullable String iface)295     public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
296         return makeHostRoute(host, null, iface);
297     }
298 
299     /**
300      * @hide
301      */
makeHostRoute(@ullable InetAddress host, @Nullable InetAddress gateway, @Nullable String iface)302     public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
303             @Nullable String iface) {
304         if (host == null) return null;
305 
306         if (host instanceof Inet4Address) {
307             return new RouteInfo(new IpPrefix(host, 32), gateway, iface);
308         } else {
309             return new RouteInfo(new IpPrefix(host, 128), gateway, iface);
310         }
311     }
312 
313     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
isHost()314     private boolean isHost() {
315         return (mDestination.getAddress() instanceof Inet4Address &&
316                 mDestination.getPrefixLength() == 32) ||
317                (mDestination.getAddress() instanceof Inet6Address &&
318                 mDestination.getPrefixLength() == 128);
319     }
320 
321     /**
322      * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
323      *
324      * @return {@link IpPrefix} specifying the destination.  This is never {@code null}.
325      */
326     @NonNull
getDestination()327     public IpPrefix getDestination() {
328         return mDestination;
329     }
330 
331     /**
332      * TODO: Convert callers to use IpPrefix and then remove.
333      * @hide
334      */
335     @NonNull
getDestinationLinkAddress()336     public LinkAddress getDestinationLinkAddress() {
337         return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
338     }
339 
340     /**
341      * Retrieves the gateway or next hop {@link InetAddress} for this route.
342      *
343      * @return {@link InetAddress} specifying the gateway or next hop.  This may be
344      *                             {@code null} for a directly-connected route."
345      */
346     @Nullable
getGateway()347     public InetAddress getGateway() {
348         return mGateway;
349     }
350 
351     /**
352      * Retrieves the interface used for this route if specified, else {@code null}.
353      *
354      * @return The name of the interface used for this route.
355      */
356     @Nullable
getInterface()357     public String getInterface() {
358         return mInterface;
359     }
360 
361     /**
362      * Retrieves the type of this route.
363      *
364      * @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
365      *
366      * @hide
367      */
368     @TestApi
369     @SystemApi
370     @RouteType
getType()371     public int getType() {
372         return mType;
373     }
374 
375     /**
376      * Indicates if this route is a default route (ie, has no destination specified).
377      *
378      * @return {@code true} if the destination has a prefix length of 0.
379      */
isDefaultRoute()380     public boolean isDefaultRoute() {
381         return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
382     }
383 
384     /**
385      * Indicates if this route is an IPv4 default route.
386      * @hide
387      */
isIPv4Default()388     public boolean isIPv4Default() {
389         return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
390     }
391 
392     /**
393      * Indicates if this route is an IPv6 default route.
394      * @hide
395      */
isIPv6Default()396     public boolean isIPv6Default() {
397         return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
398     }
399 
400     /**
401      * Indicates if this route is a host route (ie, matches only a single host address).
402      *
403      * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
404      * respectively.
405      * @hide
406      */
isHostRoute()407     public boolean isHostRoute() {
408         return mIsHost;
409     }
410 
411     /**
412      * Indicates if this route has a next hop ({@code true}) or is directly-connected
413      * ({@code false}).
414      *
415      * @return {@code true} if a gateway is specified
416      */
hasGateway()417     public boolean hasGateway() {
418         return mHasGateway;
419     }
420 
421     /**
422      * Determines whether the destination and prefix of this route includes the specified
423      * address.
424      *
425      * @param destination A {@link InetAddress} to test to see if it would match this route.
426      * @return {@code true} if the destination and prefix length cover the given address.
427      */
matches(InetAddress destination)428     public boolean matches(InetAddress destination) {
429         return mDestination.contains(destination);
430     }
431 
432     /**
433      * Find the route from a Collection of routes that best matches a given address.
434      * May return null if no routes are applicable.
435      * @param routes a Collection of RouteInfos to chose from
436      * @param dest the InetAddress your trying to get to
437      * @return the RouteInfo from the Collection that best fits the given address
438      *
439      * @hide
440      */
441     @UnsupportedAppUsage
442     @Nullable
selectBestRoute(Collection<RouteInfo> routes, InetAddress dest)443     public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
444         if ((routes == null) || (dest == null)) return null;
445 
446         RouteInfo bestRoute = null;
447         // pick a longest prefix match under same address type
448         for (RouteInfo route : routes) {
449             if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
450                 if ((bestRoute != null) &&
451                         (bestRoute.mDestination.getPrefixLength() >=
452                         route.mDestination.getPrefixLength())) {
453                     continue;
454                 }
455                 if (route.matches(dest)) bestRoute = route;
456             }
457         }
458         return bestRoute;
459     }
460 
461     /**
462      * Returns a human-readable description of this object.
463      */
toString()464     public String toString() {
465         String val = "";
466         if (mDestination != null) val = mDestination.toString();
467         if (mType == RTN_UNREACHABLE) {
468             val += " unreachable";
469         } else if (mType == RTN_THROW) {
470             val += " throw";
471         } else {
472             val += " ->";
473             if (mGateway != null) val += " " + mGateway.getHostAddress();
474             if (mInterface != null) val += " " + mInterface;
475             if (mType != RTN_UNICAST) {
476                 val += " unknown type " + mType;
477             }
478         }
479         return val;
480     }
481 
482     /**
483      * Compares this RouteInfo object against the specified object and indicates if they are equal.
484      * @return {@code true} if the objects are equal, {@code false} otherwise.
485      */
equals(Object obj)486     public boolean equals(Object obj) {
487         if (this == obj) return true;
488 
489         if (!(obj instanceof RouteInfo)) return false;
490 
491         RouteInfo target = (RouteInfo) obj;
492 
493         return Objects.equals(mDestination, target.getDestination()) &&
494                 Objects.equals(mGateway, target.getGateway()) &&
495                 Objects.equals(mInterface, target.getInterface()) &&
496                 mType == target.getType();
497     }
498 
499     /**
500      *  Returns a hashcode for this <code>RouteInfo</code> object.
501      */
hashCode()502     public int hashCode() {
503         return (mDestination.hashCode() * 41)
504                 + (mGateway == null ? 0 :mGateway.hashCode() * 47)
505                 + (mInterface == null ? 0 :mInterface.hashCode() * 67)
506                 + (mType * 71);
507     }
508 
509     /**
510      * Implement the Parcelable interface
511      */
describeContents()512     public int describeContents() {
513         return 0;
514     }
515 
516     /**
517      * Implement the Parcelable interface
518      */
writeToParcel(Parcel dest, int flags)519     public void writeToParcel(Parcel dest, int flags) {
520         dest.writeParcelable(mDestination, flags);
521         byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
522         dest.writeByteArray(gatewayBytes);
523         dest.writeString(mInterface);
524         dest.writeInt(mType);
525     }
526 
527     /**
528      * Implement the Parcelable interface.
529      */
530     public static final @android.annotation.NonNull Creator<RouteInfo> CREATOR =
531         new Creator<RouteInfo>() {
532         public RouteInfo createFromParcel(Parcel in) {
533             IpPrefix dest = in.readParcelable(null);
534 
535             InetAddress gateway = null;
536             byte[] addr = in.createByteArray();
537             try {
538                 gateway = InetAddress.getByAddress(addr);
539             } catch (UnknownHostException e) {}
540 
541             String iface = in.readString();
542             int type = in.readInt();
543 
544             return new RouteInfo(dest, gateway, iface, type);
545         }
546 
547         public RouteInfo[] newArray(int size) {
548             return new RouteInfo[size];
549         }
550     };
551 }
552