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