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