From f43396caaaae8f336bcf6fe9128a89dc7a7b0a5c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 May 2011 17:10:53 -0700 Subject: Fix the adding of host routes. We used to just add Change-Id: I991e4cc976cc2932887dd3242fd50e013d521b0a --- core/java/android/net/NetworkUtils.java | 46 ++++++++++++++++++++++ core/java/android/net/RouteInfo.java | 67 ++++++++++++++++++++++++--------- 2 files changed, 96 insertions(+), 17 deletions(-) (limited to 'core/java/android/net') diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 823d10f..fbe5379 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -225,4 +225,50 @@ public class NetworkUtils { } return addRoute(interfaceName, dstStr, prefixLength, gwStr) == 0; } + + /** + * Get InetAddress masked with prefixLength. Will never return null. + * @param IP address which will be masked with specified prefixLength + * @param prefixLength the prefixLength used to mask the IP + */ + public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { + if (address == null) { + throw new RuntimeException("getNetworkPart doesn't accept null address"); + } + + byte[] array = address.getAddress(); + + if (prefixLength < 0 || prefixLength > array.length * 8) { + throw new RuntimeException("getNetworkPart - bad prefixLength"); + } + + int offset = prefixLength / 8; + int reminder = prefixLength % 8; + byte mask = (byte)(0xFF << (8 - reminder)); + + if (offset < array.length) array[offset] = (byte)(array[offset] & mask); + + offset++; + + for (; offset < array.length; offset++) { + array[offset] = 0; + } + + InetAddress netPart = null; + try { + netPart = InetAddress.getByAddress(array); + } catch (UnknownHostException e) { + throw new RuntimeException("getNetworkPart error - " + e.toString()); + } + return netPart; + } + + /** + * Check if IP address type is consistent between two InetAddress. + * @return true if both are the same type. False otherwise. + */ + public static boolean addressTypeMatches(InetAddress left, InetAddress right) { + return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || + ((left instanceof Inet6Address) && (right instanceof Inet6Address))); + } } diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 5b10531..9c4e48b 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -23,6 +23,9 @@ import java.net.UnknownHostException; import java.net.InetAddress; import java.net.Inet4Address; import java.net.Inet6Address; + +import java.util.Collection; + /** * A simple container for route information. * @@ -44,39 +47,30 @@ public class RouteInfo implements Parcelable { public RouteInfo(LinkAddress destination, InetAddress gateway) { if (destination == null) { try { - if ((gateway != null) && (gateway instanceof Inet4Address)) { - destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32); + if ((gateway != null) || (gateway instanceof Inet4Address)) { + destination = new LinkAddress(Inet4Address.ANY, 0); } else { - destination = new LinkAddress(InetAddress.getByName("::0"), 128); + destination = new LinkAddress(Inet6Address.ANY, 0); } } catch (Exception e) {} } - mDestination = destination; + mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), + destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); mGateway = gateway; mIsDefault = isDefault(); } public RouteInfo(InetAddress gateway) { - LinkAddress destination = null; - try { - if ((gateway != null) && (gateway instanceof Inet4Address)) { - destination = new LinkAddress(InetAddress.getByName("0.0.0.0"), 32); - } else { - destination = new LinkAddress(InetAddress.getByName("::0"), 128); - } - } catch (Exception e) {} - mDestination = destination; - mGateway = gateway; - mIsDefault = isDefault(); + this(null, gateway); } private boolean isDefault() { boolean val = false; if (mGateway != null) { if (mGateway instanceof Inet4Address) { - val = (mDestination == null || mDestination.getNetworkPrefixLength() == 32); + val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); } else { - val = (mDestination == null || mDestination.getNetworkPrefixLength() == 128); + val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); } } return val; @@ -159,4 +153,43 @@ public class RouteInfo implements Parcelable { return new RouteInfo[size]; } }; + + private boolean matches(InetAddress destination) { + if (destination == null) return false; + + // if the destination is present and the route is default. + // return true + if (isDefault()) return true; + + // match the route destination and destination with prefix length + InetAddress dstNet = NetworkUtils.getNetworkPart(destination, + mDestination.getNetworkPrefixLength()); + + return mDestination.getAddress().equals(dstNet); + } + + /** + * Find the route from a Collection of routes that best matches a given address. + * May return null if no routes are applicable. + * @param routes a Collection of RouteInfos to chose from + * @param dest the InetAddress your trying to get to + * @return the RouteInfo from the Collection that best fits the given address + */ + public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { + if ((routes == null) || (dest == null)) return null; + + RouteInfo bestRoute = null; + // pick a longest prefix match under same address type + for (RouteInfo route : routes) { + if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { + if ((bestRoute != null) && + (bestRoute.mDestination.getNetworkPrefixLength() >= + route.mDestination.getNetworkPrefixLength())) { + continue; + } + if (route.matches(dest)) bestRoute = route; + } + } + return bestRoute; + } } -- cgit v1.1