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