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.os.Parcel; 20 import android.os.Parcelable; 21 22 import java.net.UnknownHostException; 23 import java.net.InetAddress; 24 import java.net.Inet4Address; 25 import java.net.Inet6Address; 26 27 import java.util.Collection; 28 import java.util.Objects; 29 30 /** 31 * Represents a network route. 32 * <p> 33 * This is used both to describe static network configuration and live network 34 * configuration information. 35 * 36 * A route contains three pieces of information: 37 * <ul> 38 * <li>a destination {@link IpPrefix} specifying the network destinations covered by this route. 39 * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6) 40 * implied by the gateway IP address. 41 * <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it 42 * indicates a directly-connected route. 43 * <li>an interface (which may be unspecified). 44 * </ul> 45 * Either the destination or the gateway may be {@code null}, but not both. If the 46 * destination and gateway are both specified, they must be of the same address family 47 * (IPv4 or IPv6). 48 */ 49 public class RouteInfo implements Parcelable { 50 /** 51 * The IP destination address for this route. 52 * TODO: Make this an IpPrefix. 53 */ 54 private final LinkAddress mDestination; 55 56 /** 57 * The gateway address for this route. 58 */ 59 private final InetAddress mGateway; 60 61 /** 62 * The interface for this route. 63 */ 64 private final String mInterface; 65 66 private final boolean mIsDefault; 67 private final boolean mIsHost; 68 private final boolean mHasGateway; 69 70 /** 71 * Constructs a RouteInfo object. 72 * 73 * If destination is null, then gateway must be specified and the 74 * constructed route is either the IPv4 default route <code>0.0.0.0</code> 75 * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default 76 * route <code>::/0</code> if gateway is an instance of 77 * {@link Inet6Address}. 78 * <p> 79 * destination and gateway may not both be null. 80 * 81 * @param destination the destination prefix 82 * @param gateway the IP address to route packets through 83 * @param iface the interface name to send packets on 84 * 85 * TODO: Convert to use IpPrefix. 86 * 87 * @hide 88 */ RouteInfo(IpPrefix destination, InetAddress gateway, String iface)89 public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { 90 this(destination == null ? null : 91 new LinkAddress(destination.getAddress(), destination.getPrefixLength()), 92 gateway, iface); 93 } 94 95 /** 96 * @hide 97 */ RouteInfo(LinkAddress destination, InetAddress gateway, String iface)98 public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { 99 if (destination == null) { 100 if (gateway != null) { 101 if (gateway instanceof Inet4Address) { 102 destination = new LinkAddress(Inet4Address.ANY, 0); 103 } else { 104 destination = new LinkAddress(Inet6Address.ANY, 0); 105 } 106 } else { 107 // no destination, no gateway. invalid. 108 throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + 109 destination); 110 } 111 } 112 if (gateway == null) { 113 if (destination.getAddress() instanceof Inet4Address) { 114 gateway = Inet4Address.ANY; 115 } else { 116 gateway = Inet6Address.ANY; 117 } 118 } 119 mHasGateway = (!gateway.isAnyLocalAddress()); 120 121 mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), 122 destination.getPrefixLength()), destination.getPrefixLength()); 123 if ((destination.getAddress() instanceof Inet4Address && 124 (gateway instanceof Inet4Address == false)) || 125 (destination.getAddress() instanceof Inet6Address && 126 (gateway instanceof Inet6Address == false))) { 127 throw new IllegalArgumentException("address family mismatch in RouteInfo constructor"); 128 } 129 mGateway = gateway; 130 mInterface = iface; 131 mIsDefault = isDefault(); 132 mIsHost = isHost(); 133 } 134 135 /** 136 * Constructs a {@code RouteInfo} object. 137 * 138 * If destination is null, then gateway must be specified and the 139 * constructed route is either the IPv4 default route <code>0.0.0.0</code> 140 * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default 141 * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}. 142 * <p> 143 * Destination and gateway may not both be null. 144 * 145 * @param destination the destination address and prefix in an {@link IpPrefix} 146 * @param gateway the {@link InetAddress} to route packets through 147 * 148 * @hide 149 */ RouteInfo(IpPrefix destination, InetAddress gateway)150 public RouteInfo(IpPrefix destination, InetAddress gateway) { 151 this(destination, gateway, null); 152 } 153 154 /** 155 * @hide 156 */ RouteInfo(LinkAddress destination, InetAddress gateway)157 public RouteInfo(LinkAddress destination, InetAddress gateway) { 158 this(destination, gateway, null); 159 } 160 161 /** 162 * Constructs a default {@code RouteInfo} object. 163 * 164 * @param gateway the {@link InetAddress} to route packets through 165 * 166 * @hide 167 */ RouteInfo(InetAddress gateway)168 public RouteInfo(InetAddress gateway) { 169 this((LinkAddress) null, gateway, null); 170 } 171 172 /** 173 * Constructs a {@code RouteInfo} object representing a direct connected subnet. 174 * 175 * @param destination the {@link IpPrefix} describing the address and prefix 176 * length of the subnet. 177 * 178 * @hide 179 */ RouteInfo(IpPrefix destination)180 public RouteInfo(IpPrefix destination) { 181 this(destination, null, null); 182 } 183 184 /** 185 * @hide 186 */ RouteInfo(LinkAddress destination)187 public RouteInfo(LinkAddress destination) { 188 this(destination, null, null); 189 } 190 191 /** 192 * @hide 193 */ makeHostRoute(InetAddress host, String iface)194 public static RouteInfo makeHostRoute(InetAddress host, String iface) { 195 return makeHostRoute(host, null, iface); 196 } 197 198 /** 199 * @hide 200 */ makeHostRoute(InetAddress host, InetAddress gateway, String iface)201 public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) { 202 if (host == null) return null; 203 204 if (host instanceof Inet4Address) { 205 return new RouteInfo(new LinkAddress(host, 32), gateway, iface); 206 } else { 207 return new RouteInfo(new LinkAddress(host, 128), gateway, iface); 208 } 209 } 210 isHost()211 private boolean isHost() { 212 return (mDestination.getAddress() instanceof Inet4Address && 213 mDestination.getPrefixLength() == 32) || 214 (mDestination.getAddress() instanceof Inet6Address && 215 mDestination.getPrefixLength() == 128); 216 } 217 isDefault()218 private boolean isDefault() { 219 boolean val = false; 220 if (mGateway != null) { 221 if (mGateway instanceof Inet4Address) { 222 val = (mDestination == null || mDestination.getPrefixLength() == 0); 223 } else { 224 val = (mDestination == null || mDestination.getPrefixLength() == 0); 225 } 226 } 227 return val; 228 } 229 230 /** 231 * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. 232 * 233 * @return {@link IpPrefix} specifying the destination. This is never {@code null}. 234 */ getDestination()235 public IpPrefix getDestination() { 236 return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength()); 237 } 238 239 /** 240 * TODO: Convert callers to use IpPrefix and then remove. 241 * @hide 242 */ getDestinationLinkAddress()243 public LinkAddress getDestinationLinkAddress() { 244 return mDestination; 245 } 246 247 /** 248 * Retrieves the gateway or next hop {@link InetAddress} for this route. 249 * 250 * @return {@link InetAddress} specifying the gateway or next hop. This may be 251 & {@code null} for a directly-connected route." 252 */ getGateway()253 public InetAddress getGateway() { 254 return mGateway; 255 } 256 257 /** 258 * Retrieves the interface used for this route if specified, else {@code null}. 259 * 260 * @return The name of the interface used for this route. 261 */ getInterface()262 public String getInterface() { 263 return mInterface; 264 } 265 266 /** 267 * Indicates if this route is a default route (ie, has no destination specified). 268 * 269 * @return {@code true} if the destination has a prefix length of 0. 270 */ isDefaultRoute()271 public boolean isDefaultRoute() { 272 return mIsDefault; 273 } 274 275 /** 276 * Indicates if this route is a host route (ie, matches only a single host address). 277 * 278 * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6, 279 * respectively. 280 * @hide 281 */ isHostRoute()282 public boolean isHostRoute() { 283 return mIsHost; 284 } 285 286 /** 287 * Indicates if this route has a next hop ({@code true}) or is directly-connected 288 * ({@code false}). 289 * 290 * @return {@code true} if a gateway is specified 291 * @hide 292 */ hasGateway()293 public boolean hasGateway() { 294 return mHasGateway; 295 } 296 297 /** 298 * Determines whether the destination and prefix of this route includes the specified 299 * address. 300 * 301 * @param destination A {@link InetAddress} to test to see if it would match this route. 302 * @return {@code true} if the destination and prefix length cover the given address. 303 */ matches(InetAddress destination)304 public boolean matches(InetAddress destination) { 305 if (destination == null) return false; 306 307 // match the route destination and destination with prefix length 308 InetAddress dstNet = NetworkUtils.getNetworkPart(destination, 309 mDestination.getPrefixLength()); 310 311 return mDestination.getAddress().equals(dstNet); 312 } 313 314 /** 315 * Find the route from a Collection of routes that best matches a given address. 316 * May return null if no routes are applicable. 317 * @param routes a Collection of RouteInfos to chose from 318 * @param dest the InetAddress your trying to get to 319 * @return the RouteInfo from the Collection that best fits the given address 320 * 321 * @hide 322 */ selectBestRoute(Collection<RouteInfo> routes, InetAddress dest)323 public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) { 324 if ((routes == null) || (dest == null)) return null; 325 326 RouteInfo bestRoute = null; 327 // pick a longest prefix match under same address type 328 for (RouteInfo route : routes) { 329 if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { 330 if ((bestRoute != null) && 331 (bestRoute.mDestination.getPrefixLength() >= 332 route.mDestination.getPrefixLength())) { 333 continue; 334 } 335 if (route.matches(dest)) bestRoute = route; 336 } 337 } 338 return bestRoute; 339 } 340 341 /** 342 * Returns a human-readable description of this object. 343 */ toString()344 public String toString() { 345 String val = ""; 346 if (mDestination != null) val = mDestination.toString(); 347 val += " ->"; 348 if (mGateway != null) val += " " + mGateway.getHostAddress(); 349 if (mInterface != null) val += " " + mInterface; 350 return val; 351 } 352 353 /** 354 * Compares this RouteInfo object against the specified object and indicates if they are equal. 355 * @return {@code true} if the objects are equal, {@code false} otherwise. 356 */ equals(Object obj)357 public boolean equals(Object obj) { 358 if (this == obj) return true; 359 360 if (!(obj instanceof RouteInfo)) return false; 361 362 RouteInfo target = (RouteInfo) obj; 363 364 return Objects.equals(mDestination, target.getDestinationLinkAddress()) && 365 Objects.equals(mGateway, target.getGateway()) && 366 Objects.equals(mInterface, target.getInterface()); 367 } 368 369 /** 370 * Returns a hashcode for this <code>RouteInfo</code> object. 371 */ hashCode()372 public int hashCode() { 373 return (mDestination == null ? 0 : mDestination.hashCode() * 41) 374 + (mGateway == null ? 0 :mGateway.hashCode() * 47) 375 + (mInterface == null ? 0 :mInterface.hashCode() * 67) 376 + (mIsDefault ? 3 : 7); 377 } 378 379 /** 380 * Implement the Parcelable interface 381 * @hide 382 */ describeContents()383 public int describeContents() { 384 return 0; 385 } 386 387 /** 388 * Implement the Parcelable interface 389 * @hide 390 */ writeToParcel(Parcel dest, int flags)391 public void writeToParcel(Parcel dest, int flags) { 392 if (mDestination == null) { 393 dest.writeByte((byte) 0); 394 } else { 395 dest.writeByte((byte) 1); 396 dest.writeByteArray(mDestination.getAddress().getAddress()); 397 dest.writeInt(mDestination.getPrefixLength()); 398 } 399 400 if (mGateway == null) { 401 dest.writeByte((byte) 0); 402 } else { 403 dest.writeByte((byte) 1); 404 dest.writeByteArray(mGateway.getAddress()); 405 } 406 407 dest.writeString(mInterface); 408 } 409 410 /** 411 * Implement the Parcelable interface. 412 * @hide 413 */ 414 public static final Creator<RouteInfo> CREATOR = 415 new Creator<RouteInfo>() { 416 public RouteInfo createFromParcel(Parcel in) { 417 InetAddress destAddr = null; 418 int prefix = 0; 419 InetAddress gateway = null; 420 421 if (in.readByte() == 1) { 422 byte[] addr = in.createByteArray(); 423 prefix = in.readInt(); 424 425 try { 426 destAddr = InetAddress.getByAddress(addr); 427 } catch (UnknownHostException e) {} 428 } 429 430 if (in.readByte() == 1) { 431 byte[] addr = in.createByteArray(); 432 433 try { 434 gateway = InetAddress.getByAddress(addr); 435 } catch (UnknownHostException e) {} 436 } 437 438 String iface = in.readString(); 439 440 LinkAddress dest = null; 441 442 if (destAddr != null) { 443 dest = new LinkAddress(destAddr, prefix); 444 } 445 446 return new RouteInfo(dest, gateway, iface); 447 } 448 449 public RouteInfo[] newArray(int size) { 450 return new RouteInfo[size]; 451 } 452 }; 453 } 454