• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
29 /**
30  * A simple container for route information.
31  *
32  * In order to be used, a route must have a destination prefix and:
33  *
34  * - A gateway address (next-hop, for gatewayed routes), or
35  * - An interface (for directly-connected routes), or
36  * - Both a gateway and an interface.
37  *
38  * This class does not enforce these constraints because there is code that
39  * uses RouteInfo objects to store directly-connected routes without interfaces.
40  * Such objects cannot be used directly, but can be put into a LinkProperties
41  * object which then specifies the interface.
42  *
43  * @hide
44  */
45 public class RouteInfo implements Parcelable {
46     /**
47      * The IP destination address for this route.
48      */
49     private final LinkAddress mDestination;
50 
51     /**
52      * The gateway address for this route.
53      */
54     private final InetAddress mGateway;
55 
56     /**
57      * The interface for this route.
58      */
59     private final String mInterface;
60 
61     private final boolean mIsDefault;
62     private final boolean mIsHost;
63     private final boolean mHasGateway;
64 
65     /**
66      * Constructs a RouteInfo object.
67      *
68      * If destination is null, then gateway must be specified and the
69      * constructed route is either the IPv4 default route <code>0.0.0.0</code>
70      * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default
71      * route <code>::/0</code> if gateway is an instance of
72      * {@link Inet6Address}.
73      *
74      * destination and gateway may not both be null.
75      *
76      * @param destination the destination prefix
77      * @param gateway the IP address to route packets through
78      * @param iface the interface name to send packets on
79      */
RouteInfo(LinkAddress destination, InetAddress gateway, String iface)80     public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
81         if (destination == null) {
82             if (gateway != null) {
83                 if (gateway instanceof Inet4Address) {
84                     destination = new LinkAddress(Inet4Address.ANY, 0);
85                 } else {
86                     destination = new LinkAddress(Inet6Address.ANY, 0);
87                 }
88             } else {
89                 // no destination, no gateway. invalid.
90                 throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
91                                                    destination);
92             }
93         }
94         if (gateway == null) {
95             if (destination.getAddress() instanceof Inet4Address) {
96                 gateway = Inet4Address.ANY;
97             } else {
98                 gateway = Inet6Address.ANY;
99             }
100         }
101         mHasGateway = (!gateway.isAnyLocalAddress());
102 
103         mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
104                 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
105         mGateway = gateway;
106         mInterface = iface;
107         mIsDefault = isDefault();
108         mIsHost = isHost();
109     }
110 
RouteInfo(LinkAddress destination, InetAddress gateway)111     public RouteInfo(LinkAddress destination, InetAddress gateway) {
112         this(destination, gateway, null);
113     }
114 
RouteInfo(InetAddress gateway)115     public RouteInfo(InetAddress gateway) {
116         this(null, gateway, null);
117     }
118 
RouteInfo(LinkAddress host)119     public RouteInfo(LinkAddress host) {
120         this(host, null, null);
121     }
122 
makeHostRoute(InetAddress host, String iface)123     public static RouteInfo makeHostRoute(InetAddress host, String iface) {
124         return makeHostRoute(host, null, iface);
125     }
126 
makeHostRoute(InetAddress host, InetAddress gateway, String iface)127     public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
128         if (host == null) return null;
129 
130         if (host instanceof Inet4Address) {
131             return new RouteInfo(new LinkAddress(host, 32), gateway, iface);
132         } else {
133             return new RouteInfo(new LinkAddress(host, 128), gateway, iface);
134         }
135     }
136 
isHost()137     private boolean isHost() {
138         return (mDestination.getAddress() instanceof Inet4Address &&
139                 mDestination.getNetworkPrefixLength() == 32) ||
140                (mDestination.getAddress() instanceof Inet6Address &&
141                 mDestination.getNetworkPrefixLength() == 128);
142     }
143 
isDefault()144     private boolean isDefault() {
145         boolean val = false;
146         if (mGateway != null) {
147             if (mGateway instanceof Inet4Address) {
148                 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
149             } else {
150                 val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
151             }
152         }
153         return val;
154     }
155 
156 
getDestination()157     public LinkAddress getDestination() {
158         return mDestination;
159     }
160 
getGateway()161     public InetAddress getGateway() {
162         return mGateway;
163     }
164 
getInterface()165     public String getInterface() {
166         return mInterface;
167     }
168 
isDefaultRoute()169     public boolean isDefaultRoute() {
170         return mIsDefault;
171     }
172 
isHostRoute()173     public boolean isHostRoute() {
174         return mIsHost;
175     }
176 
hasGateway()177     public boolean hasGateway() {
178         return mHasGateway;
179     }
180 
toString()181     public String toString() {
182         String val = "";
183         if (mDestination != null) val = mDestination.toString();
184         if (mGateway != null) val += " -> " + mGateway.getHostAddress();
185         return val;
186     }
187 
describeContents()188     public int describeContents() {
189         return 0;
190     }
191 
writeToParcel(Parcel dest, int flags)192     public void writeToParcel(Parcel dest, int flags) {
193         if (mDestination == null) {
194             dest.writeByte((byte) 0);
195         } else {
196             dest.writeByte((byte) 1);
197             dest.writeByteArray(mDestination.getAddress().getAddress());
198             dest.writeInt(mDestination.getNetworkPrefixLength());
199         }
200 
201         if (mGateway == null) {
202             dest.writeByte((byte) 0);
203         } else {
204             dest.writeByte((byte) 1);
205             dest.writeByteArray(mGateway.getAddress());
206         }
207 
208         dest.writeString(mInterface);
209     }
210 
211     @Override
equals(Object obj)212     public boolean equals(Object obj) {
213         if (this == obj) return true;
214 
215         if (!(obj instanceof RouteInfo)) return false;
216 
217         RouteInfo target = (RouteInfo) obj;
218 
219         boolean sameDestination = ( mDestination == null) ?
220                 target.getDestination() == null
221                 : mDestination.equals(target.getDestination());
222 
223         boolean sameAddress = (mGateway == null) ?
224                 target.getGateway() == null
225                 : mGateway.equals(target.getGateway());
226 
227         boolean sameInterface = (mInterface == null) ?
228                 target.getInterface() == null
229                 : mInterface.equals(target.getInterface());
230 
231         return sameDestination && sameAddress && sameInterface
232             && mIsDefault == target.mIsDefault;
233     }
234 
235     @Override
hashCode()236     public int hashCode() {
237         return (mDestination == null ? 0 : mDestination.hashCode() * 41)
238             + (mGateway == null ? 0 :mGateway.hashCode() * 47)
239             + (mInterface == null ? 0 :mInterface.hashCode() * 67)
240             + (mIsDefault ? 3 : 7);
241     }
242 
243     public static final Creator<RouteInfo> CREATOR =
244         new Creator<RouteInfo>() {
245         public RouteInfo createFromParcel(Parcel in) {
246             InetAddress destAddr = null;
247             int prefix = 0;
248             InetAddress gateway = null;
249 
250             if (in.readByte() == 1) {
251                 byte[] addr = in.createByteArray();
252                 prefix = in.readInt();
253 
254                 try {
255                     destAddr = InetAddress.getByAddress(addr);
256                 } catch (UnknownHostException e) {}
257             }
258 
259             if (in.readByte() == 1) {
260                 byte[] addr = in.createByteArray();
261 
262                 try {
263                     gateway = InetAddress.getByAddress(addr);
264                 } catch (UnknownHostException e) {}
265             }
266 
267             String iface = in.readString();
268 
269             LinkAddress dest = null;
270 
271             if (destAddr != null) {
272                 dest = new LinkAddress(destAddr, prefix);
273             }
274 
275             return new RouteInfo(dest, gateway, iface);
276         }
277 
278         public RouteInfo[] newArray(int size) {
279             return new RouteInfo[size];
280         }
281     };
282 
matches(InetAddress destination)283     protected boolean matches(InetAddress destination) {
284         if (destination == null) return false;
285 
286         // match the route destination and destination with prefix length
287         InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
288                 mDestination.getNetworkPrefixLength());
289 
290         return mDestination.getAddress().equals(dstNet);
291     }
292 
293     /**
294      * Find the route from a Collection of routes that best matches a given address.
295      * May return null if no routes are applicable.
296      * @param routes a Collection of RouteInfos to chose from
297      * @param dest the InetAddress your trying to get to
298      * @return the RouteInfo from the Collection that best fits the given address
299      */
selectBestRoute(Collection<RouteInfo> routes, InetAddress dest)300     public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
301         if ((routes == null) || (dest == null)) return null;
302 
303         RouteInfo bestRoute = null;
304         // pick a longest prefix match under same address type
305         for (RouteInfo route : routes) {
306             if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
307                 if ((bestRoute != null) &&
308                         (bestRoute.mDestination.getNetworkPrefixLength() >=
309                         route.mDestination.getNetworkPrefixLength())) {
310                     continue;
311                 }
312                 if (route.matches(dest)) bestRoute = route;
313             }
314         }
315         return bestRoute;
316     }
317 }
318