Home | History | Annotate | Download | only in net
      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
    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
    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
    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      */
    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
    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
    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      */
    274     public RouteInfo(@NonNull IpPrefix destination) {
    275         this(destination, null, null);
    276     }
    277 
    278     /**
    279      * @hide
    280      */
    281     public RouteInfo(@NonNull LinkAddress destination) {
    282         this(destination, null, null);
    283     }
    284 
    285     /**
    286      * @hide
    287      */
    288     public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
    289         this(destination, null, null, type);
    290     }
    291 
    292     /**
    293      * @hide
    294      */
    295     public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
    296         return makeHostRoute(host, null, iface);
    297     }
    298 
    299     /**
    300      * @hide
    301      */
    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)
    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
    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
    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
    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
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    512     public int describeContents() {
    513         return 0;
    514     }
    515 
    516     /**
    517      * Implement the Parcelable interface
    518      */
    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