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