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