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