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