Loading Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -81,12 +81,12 @@ java_defaults { name: "NetworkStackAndroidLibraryDefaults", srcs: [ ":framework-networkstack-shared-srcs", ":services-networkstack-shared-srcs", ":statslog-networkstack-java-gen", ], static_libs: [ "androidx.annotation_annotation", "netd_aidl_interface-V2-java", "netlink-client", "networkstack-client", "datastallprotosnano", "networkstackprotosnano", Loading common/moduleutils/src/android/net/ip/InterfaceController.java 0 → 100644 +193 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.ip; import android.net.INetd; import android.net.InterfaceConfigurationParcel; import android.net.LinkAddress; import android.net.util.SharedLog; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.system.OsConstants; import java.net.Inet4Address; import java.net.InetAddress; /** * Encapsulates the multiple IP configuration operations performed on an interface. * * TODO: refactor/eliminate the redundant ways to set and clear addresses. * * @hide */ public class InterfaceController { private final static boolean DBG = false; private final String mIfName; private final INetd mNetd; private final SharedLog mLog; public InterfaceController(String ifname, INetd netd, SharedLog log) { mIfName = ifname; mNetd = netd; mLog = log; } private boolean setInterfaceAddress(LinkAddress addr) { final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); ifConfig.ifName = mIfName; ifConfig.ipv4Addr = addr.getAddress().getHostAddress(); ifConfig.prefixLength = addr.getPrefixLength(); ifConfig.hwAddr = ""; ifConfig.flags = new String[0]; try { mNetd.interfaceSetCfg(ifConfig); } catch (RemoteException | ServiceSpecificException e) { logError("Setting IPv4 address to %s/%d failed: %s", ifConfig.ipv4Addr, ifConfig.prefixLength, e); return false; } return true; } /** * Set the IPv4 address of the interface. */ public boolean setIPv4Address(LinkAddress address) { if (!(address.getAddress() instanceof Inet4Address)) { return false; } return setInterfaceAddress(address); } /** * Clear the IPv4Address of the interface. */ public boolean clearIPv4Address() { return setInterfaceAddress(new LinkAddress("0.0.0.0/0")); } private boolean setEnableIPv6(boolean enabled) { try { mNetd.interfaceSetEnableIPv6(mIfName, enabled); } catch (RemoteException | ServiceSpecificException e) { logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e); return false; } return true; } /** * Enable IPv6 on the interface. */ public boolean enableIPv6() { return setEnableIPv6(true); } /** * Disable IPv6 on the interface. */ public boolean disableIPv6() { return setEnableIPv6(false); } /** * Enable or disable IPv6 privacy extensions on the interface. * @param enabled Whether the extensions should be enabled. */ public boolean setIPv6PrivacyExtensions(boolean enabled) { try { mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled); } catch (RemoteException | ServiceSpecificException e) { logError("error %s IPv6 privacy extensions: %s", (enabled ? "enabling" : "disabling"), e); return false; } return true; } /** * Set IPv6 address generation mode on the interface. * * <p>IPv6 should be disabled before changing the mode. */ public boolean setIPv6AddrGenModeIfSupported(int mode) { try { mNetd.setIPv6AddrGenMode(mIfName, mode); } catch (RemoteException e) { logError("Unable to set IPv6 addrgen mode: %s", e); return false; } catch (ServiceSpecificException e) { if (e.errorCode != OsConstants.EOPNOTSUPP) { logError("Unable to set IPv6 addrgen mode: %s", e); return false; } } return true; } /** * Add an address to the interface. */ public boolean addAddress(LinkAddress addr) { return addAddress(addr.getAddress(), addr.getPrefixLength()); } /** * Add an address to the interface. */ public boolean addAddress(InetAddress ip, int prefixLen) { try { mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen); } catch (ServiceSpecificException | RemoteException e) { logError("failed to add %s/%d: %s", ip, prefixLen, e); return false; } return true; } /** * Remove an address from the interface. */ public boolean removeAddress(InetAddress ip, int prefixLen) { try { mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen); } catch (ServiceSpecificException | RemoteException e) { logError("failed to remove %s/%d: %s", ip, prefixLen, e); return false; } return true; } /** * Remove all addresses from the interface. */ public boolean clearAllAddresses() { try { mNetd.interfaceClearAddrs(mIfName); } catch (Exception e) { logError("Failed to clear addresses: %s", e); return false; } return true; } private void logError(String fmt, Object... args) { mLog.e(String.format(fmt, args)); } } common/moduleutils/src/android/net/shared/InitialConfiguration.java 0 → 100644 +240 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.shared; import static android.net.shared.ParcelableUtil.fromParcelableArray; import static android.net.shared.ParcelableUtil.toParcelableArray; import static android.text.TextUtils.join; import android.net.InetAddresses; import android.net.InitialConfigurationParcelable; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.RouteInfo; import java.net.Inet4Address; import java.net.InetAddress; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; /** @hide */ public class InitialConfiguration { public final Set<LinkAddress> ipAddresses = new HashSet<>(); public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>(); public final Set<InetAddress> dnsServers = new HashSet<>(); private static final int RFC6177_MIN_PREFIX_LENGTH = 48; private static final int RFC7421_PREFIX_LENGTH = 64; public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::"); /** * Create a InitialConfiguration that is a copy of the specified configuration. */ public static InitialConfiguration copy(InitialConfiguration config) { if (config == null) { return null; } InitialConfiguration configCopy = new InitialConfiguration(); configCopy.ipAddresses.addAll(config.ipAddresses); configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes); configCopy.dnsServers.addAll(config.dnsServers); return configCopy; } @Override public String toString() { return String.format( "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})", join(", ", ipAddresses), join(", ", directlyConnectedRoutes), join(", ", dnsServers)); } /** * Tests whether the contents of this IpConfiguration represent a valid configuration. */ public boolean isValid() { if (ipAddresses.isEmpty()) { return false; } // For every IP address, there must be at least one prefix containing that address. for (LinkAddress addr : ipAddresses) { if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) { return false; } } // For every dns server, there must be at least one prefix containing that address. for (InetAddress addr : dnsServers) { if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) { return false; } } // All IPv6 LinkAddresses have an RFC7421-suitable prefix length // (read: compliant with RFC4291#section2.5.4). if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) { return false; } // If directlyConnectedRoutes contains an IPv6 default route // then ipAddresses MUST contain at least one non-ULA GUA. if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute) && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) { return false; } // The prefix length of routes in directlyConnectedRoutes be within reasonable // bounds for IPv6: /48-/64 just as we’d accept in RIOs. if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) { return false; } // There no more than one IPv4 address if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) { return false; } return true; } /** * @return true if the given list of addressess and routes satisfies provisioning for this * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality * because addresses and routes seen by Netlink will contain additional fields like flags, * interfaces, and so on. If this InitialConfiguration has no IP address specified, the * provisioning check always fails. * * If the given list of routes is null, only addresses are taken into considerations. */ public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) { if (ipAddresses.isEmpty()) { return false; } for (LinkAddress addr : ipAddresses) { if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) { return false; } } if (routes != null) { for (IpPrefix prefix : directlyConnectedRoutes) { if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) { return false; } } } return true; } /** * Convert this configuration to a {@link InitialConfigurationParcelable}. */ public InitialConfigurationParcelable toStableParcelable() { final InitialConfigurationParcelable p = new InitialConfigurationParcelable(); p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]); p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]); p.dnsServers = toParcelableArray( dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class); return p; } /** * Create an instance of {@link InitialConfiguration} based on the contents of the specified * {@link InitialConfigurationParcelable}. */ public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) { if (p == null) return null; final InitialConfiguration config = new InitialConfiguration(); config.ipAddresses.addAll(Arrays.asList(p.ipAddresses)); config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes)); config.dnsServers.addAll( fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress)); return config; } @Override public boolean equals(Object obj) { if (!(obj instanceof InitialConfiguration)) return false; final InitialConfiguration other = (InitialConfiguration) obj; return ipAddresses.equals(other.ipAddresses) && directlyConnectedRoutes.equals(other.directlyConnectedRoutes) && dnsServers.equals(other.dnsServers); } private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) { return !route.hasGateway() && prefix.equals(route.getDestination()); } private static boolean isPrefixLengthCompliant(LinkAddress addr) { return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength()); } private static boolean isPrefixLengthCompliant(IpPrefix prefix) { return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength()); } private static boolean isCompliantIPv6PrefixLength(int prefixLength) { return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength) && (prefixLength <= RFC7421_PREFIX_LENGTH); } private static boolean isIPv4(IpPrefix prefix) { return prefix.getAddress() instanceof Inet4Address; } private static boolean isIPv4(LinkAddress addr) { return addr.getAddress() instanceof Inet4Address; } private static boolean isIPv6DefaultRoute(IpPrefix prefix) { return prefix.getAddress().equals(INET6_ANY); } private static boolean isIPv6GUA(LinkAddress addr) { return addr.isIpv6() && addr.isGlobalPreferred(); } // TODO: extract out into CollectionUtils. /** * Indicate whether any element of the specified iterable verifies the specified predicate. */ public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) { for (T t : coll) { if (fn.test(t)) { return true; } } return false; } /** * Indicate whether all elements of the specified iterable verifies the specified predicate. */ public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) { return !any(coll, not(fn)); } /** * Create a predicate that returns the opposite value of the specified predicate. */ public static <T> Predicate<T> not(Predicate<T> fn) { return (t) -> !fn.test(t); } } common/moduleutils/src/android/net/shared/IpConfigurationParcelableUtil.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.shared; import android.annotation.Nullable; import android.net.DhcpResults; import android.net.DhcpResultsParcelable; import android.net.InetAddresses; import java.net.Inet4Address; import java.net.InetAddress; /** * Collection of utility methods to convert to and from stable AIDL parcelables for IpClient * configuration classes. * @hide */ public final class IpConfigurationParcelableUtil { /** * Convert DhcpResults to a DhcpResultsParcelable. */ public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) { if (results == null) return null; final DhcpResultsParcelable p = new DhcpResultsParcelable(); p.baseConfiguration = results.toStaticIpConfiguration(); p.leaseDuration = results.leaseDuration; p.mtu = results.mtu; p.serverAddress = parcelAddress(results.serverAddress); p.vendorInfo = results.vendorInfo; p.serverHostName = results.serverHostName; return p; } /** * Convert a DhcpResultsParcelable to DhcpResults. */ public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) { if (p == null) return null; final DhcpResults results = new DhcpResults(p.baseConfiguration); results.leaseDuration = p.leaseDuration; results.mtu = p.mtu; results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress); results.vendorInfo = p.vendorInfo; results.serverHostName = p.serverHostName; return results; } /** * Convert InetAddress to String. * TODO: have an InetAddressParcelable */ public static String parcelAddress(@Nullable InetAddress addr) { if (addr == null) return null; return addr.getHostAddress(); } /** * Convert String to InetAddress. * TODO: have an InetAddressParcelable */ public static InetAddress unparcelAddress(@Nullable String addr) { if (addr == null) return null; return InetAddresses.parseNumericAddress(addr); } } common/moduleutils/src/android/net/shared/LinkPropertiesParcelableUtil.java 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.shared; import android.annotation.Nullable; import android.net.LinkProperties; import android.net.ProxyInfo; /** * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties * and its attributes. * @hide */ public final class LinkPropertiesParcelableUtil { // Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable // TODO: remove the following methods after migrating clients. /** * @deprecated conversion to stable parcelable is no longer necessary. */ @Deprecated public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) { return lp; } /** * @deprecated conversion to stable parcelable is no longer necessary. */ @Deprecated public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) { return info; } } Loading
Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -81,12 +81,12 @@ java_defaults { name: "NetworkStackAndroidLibraryDefaults", srcs: [ ":framework-networkstack-shared-srcs", ":services-networkstack-shared-srcs", ":statslog-networkstack-java-gen", ], static_libs: [ "androidx.annotation_annotation", "netd_aidl_interface-V2-java", "netlink-client", "networkstack-client", "datastallprotosnano", "networkstackprotosnano", Loading
common/moduleutils/src/android/net/ip/InterfaceController.java 0 → 100644 +193 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.ip; import android.net.INetd; import android.net.InterfaceConfigurationParcel; import android.net.LinkAddress; import android.net.util.SharedLog; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.system.OsConstants; import java.net.Inet4Address; import java.net.InetAddress; /** * Encapsulates the multiple IP configuration operations performed on an interface. * * TODO: refactor/eliminate the redundant ways to set and clear addresses. * * @hide */ public class InterfaceController { private final static boolean DBG = false; private final String mIfName; private final INetd mNetd; private final SharedLog mLog; public InterfaceController(String ifname, INetd netd, SharedLog log) { mIfName = ifname; mNetd = netd; mLog = log; } private boolean setInterfaceAddress(LinkAddress addr) { final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); ifConfig.ifName = mIfName; ifConfig.ipv4Addr = addr.getAddress().getHostAddress(); ifConfig.prefixLength = addr.getPrefixLength(); ifConfig.hwAddr = ""; ifConfig.flags = new String[0]; try { mNetd.interfaceSetCfg(ifConfig); } catch (RemoteException | ServiceSpecificException e) { logError("Setting IPv4 address to %s/%d failed: %s", ifConfig.ipv4Addr, ifConfig.prefixLength, e); return false; } return true; } /** * Set the IPv4 address of the interface. */ public boolean setIPv4Address(LinkAddress address) { if (!(address.getAddress() instanceof Inet4Address)) { return false; } return setInterfaceAddress(address); } /** * Clear the IPv4Address of the interface. */ public boolean clearIPv4Address() { return setInterfaceAddress(new LinkAddress("0.0.0.0/0")); } private boolean setEnableIPv6(boolean enabled) { try { mNetd.interfaceSetEnableIPv6(mIfName, enabled); } catch (RemoteException | ServiceSpecificException e) { logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e); return false; } return true; } /** * Enable IPv6 on the interface. */ public boolean enableIPv6() { return setEnableIPv6(true); } /** * Disable IPv6 on the interface. */ public boolean disableIPv6() { return setEnableIPv6(false); } /** * Enable or disable IPv6 privacy extensions on the interface. * @param enabled Whether the extensions should be enabled. */ public boolean setIPv6PrivacyExtensions(boolean enabled) { try { mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled); } catch (RemoteException | ServiceSpecificException e) { logError("error %s IPv6 privacy extensions: %s", (enabled ? "enabling" : "disabling"), e); return false; } return true; } /** * Set IPv6 address generation mode on the interface. * * <p>IPv6 should be disabled before changing the mode. */ public boolean setIPv6AddrGenModeIfSupported(int mode) { try { mNetd.setIPv6AddrGenMode(mIfName, mode); } catch (RemoteException e) { logError("Unable to set IPv6 addrgen mode: %s", e); return false; } catch (ServiceSpecificException e) { if (e.errorCode != OsConstants.EOPNOTSUPP) { logError("Unable to set IPv6 addrgen mode: %s", e); return false; } } return true; } /** * Add an address to the interface. */ public boolean addAddress(LinkAddress addr) { return addAddress(addr.getAddress(), addr.getPrefixLength()); } /** * Add an address to the interface. */ public boolean addAddress(InetAddress ip, int prefixLen) { try { mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen); } catch (ServiceSpecificException | RemoteException e) { logError("failed to add %s/%d: %s", ip, prefixLen, e); return false; } return true; } /** * Remove an address from the interface. */ public boolean removeAddress(InetAddress ip, int prefixLen) { try { mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen); } catch (ServiceSpecificException | RemoteException e) { logError("failed to remove %s/%d: %s", ip, prefixLen, e); return false; } return true; } /** * Remove all addresses from the interface. */ public boolean clearAllAddresses() { try { mNetd.interfaceClearAddrs(mIfName); } catch (Exception e) { logError("Failed to clear addresses: %s", e); return false; } return true; } private void logError(String fmt, Object... args) { mLog.e(String.format(fmt, args)); } }
common/moduleutils/src/android/net/shared/InitialConfiguration.java 0 → 100644 +240 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.shared; import static android.net.shared.ParcelableUtil.fromParcelableArray; import static android.net.shared.ParcelableUtil.toParcelableArray; import static android.text.TextUtils.join; import android.net.InetAddresses; import android.net.InitialConfigurationParcelable; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.RouteInfo; import java.net.Inet4Address; import java.net.InetAddress; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; /** @hide */ public class InitialConfiguration { public final Set<LinkAddress> ipAddresses = new HashSet<>(); public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>(); public final Set<InetAddress> dnsServers = new HashSet<>(); private static final int RFC6177_MIN_PREFIX_LENGTH = 48; private static final int RFC7421_PREFIX_LENGTH = 64; public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::"); /** * Create a InitialConfiguration that is a copy of the specified configuration. */ public static InitialConfiguration copy(InitialConfiguration config) { if (config == null) { return null; } InitialConfiguration configCopy = new InitialConfiguration(); configCopy.ipAddresses.addAll(config.ipAddresses); configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes); configCopy.dnsServers.addAll(config.dnsServers); return configCopy; } @Override public String toString() { return String.format( "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})", join(", ", ipAddresses), join(", ", directlyConnectedRoutes), join(", ", dnsServers)); } /** * Tests whether the contents of this IpConfiguration represent a valid configuration. */ public boolean isValid() { if (ipAddresses.isEmpty()) { return false; } // For every IP address, there must be at least one prefix containing that address. for (LinkAddress addr : ipAddresses) { if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) { return false; } } // For every dns server, there must be at least one prefix containing that address. for (InetAddress addr : dnsServers) { if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) { return false; } } // All IPv6 LinkAddresses have an RFC7421-suitable prefix length // (read: compliant with RFC4291#section2.5.4). if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) { return false; } // If directlyConnectedRoutes contains an IPv6 default route // then ipAddresses MUST contain at least one non-ULA GUA. if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute) && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) { return false; } // The prefix length of routes in directlyConnectedRoutes be within reasonable // bounds for IPv6: /48-/64 just as we’d accept in RIOs. if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) { return false; } // There no more than one IPv4 address if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) { return false; } return true; } /** * @return true if the given list of addressess and routes satisfies provisioning for this * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality * because addresses and routes seen by Netlink will contain additional fields like flags, * interfaces, and so on. If this InitialConfiguration has no IP address specified, the * provisioning check always fails. * * If the given list of routes is null, only addresses are taken into considerations. */ public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) { if (ipAddresses.isEmpty()) { return false; } for (LinkAddress addr : ipAddresses) { if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) { return false; } } if (routes != null) { for (IpPrefix prefix : directlyConnectedRoutes) { if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) { return false; } } } return true; } /** * Convert this configuration to a {@link InitialConfigurationParcelable}. */ public InitialConfigurationParcelable toStableParcelable() { final InitialConfigurationParcelable p = new InitialConfigurationParcelable(); p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]); p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]); p.dnsServers = toParcelableArray( dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class); return p; } /** * Create an instance of {@link InitialConfiguration} based on the contents of the specified * {@link InitialConfigurationParcelable}. */ public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) { if (p == null) return null; final InitialConfiguration config = new InitialConfiguration(); config.ipAddresses.addAll(Arrays.asList(p.ipAddresses)); config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes)); config.dnsServers.addAll( fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress)); return config; } @Override public boolean equals(Object obj) { if (!(obj instanceof InitialConfiguration)) return false; final InitialConfiguration other = (InitialConfiguration) obj; return ipAddresses.equals(other.ipAddresses) && directlyConnectedRoutes.equals(other.directlyConnectedRoutes) && dnsServers.equals(other.dnsServers); } private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) { return !route.hasGateway() && prefix.equals(route.getDestination()); } private static boolean isPrefixLengthCompliant(LinkAddress addr) { return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength()); } private static boolean isPrefixLengthCompliant(IpPrefix prefix) { return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength()); } private static boolean isCompliantIPv6PrefixLength(int prefixLength) { return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength) && (prefixLength <= RFC7421_PREFIX_LENGTH); } private static boolean isIPv4(IpPrefix prefix) { return prefix.getAddress() instanceof Inet4Address; } private static boolean isIPv4(LinkAddress addr) { return addr.getAddress() instanceof Inet4Address; } private static boolean isIPv6DefaultRoute(IpPrefix prefix) { return prefix.getAddress().equals(INET6_ANY); } private static boolean isIPv6GUA(LinkAddress addr) { return addr.isIpv6() && addr.isGlobalPreferred(); } // TODO: extract out into CollectionUtils. /** * Indicate whether any element of the specified iterable verifies the specified predicate. */ public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) { for (T t : coll) { if (fn.test(t)) { return true; } } return false; } /** * Indicate whether all elements of the specified iterable verifies the specified predicate. */ public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) { return !any(coll, not(fn)); } /** * Create a predicate that returns the opposite value of the specified predicate. */ public static <T> Predicate<T> not(Predicate<T> fn) { return (t) -> !fn.test(t); } }
common/moduleutils/src/android/net/shared/IpConfigurationParcelableUtil.java 0 → 100644 +79 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.shared; import android.annotation.Nullable; import android.net.DhcpResults; import android.net.DhcpResultsParcelable; import android.net.InetAddresses; import java.net.Inet4Address; import java.net.InetAddress; /** * Collection of utility methods to convert to and from stable AIDL parcelables for IpClient * configuration classes. * @hide */ public final class IpConfigurationParcelableUtil { /** * Convert DhcpResults to a DhcpResultsParcelable. */ public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) { if (results == null) return null; final DhcpResultsParcelable p = new DhcpResultsParcelable(); p.baseConfiguration = results.toStaticIpConfiguration(); p.leaseDuration = results.leaseDuration; p.mtu = results.mtu; p.serverAddress = parcelAddress(results.serverAddress); p.vendorInfo = results.vendorInfo; p.serverHostName = results.serverHostName; return p; } /** * Convert a DhcpResultsParcelable to DhcpResults. */ public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) { if (p == null) return null; final DhcpResults results = new DhcpResults(p.baseConfiguration); results.leaseDuration = p.leaseDuration; results.mtu = p.mtu; results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress); results.vendorInfo = p.vendorInfo; results.serverHostName = p.serverHostName; return results; } /** * Convert InetAddress to String. * TODO: have an InetAddressParcelable */ public static String parcelAddress(@Nullable InetAddress addr) { if (addr == null) return null; return addr.getHostAddress(); } /** * Convert String to InetAddress. * TODO: have an InetAddressParcelable */ public static InetAddress unparcelAddress(@Nullable String addr) { if (addr == null) return null; return InetAddresses.parseNumericAddress(addr); } }
common/moduleutils/src/android/net/shared/LinkPropertiesParcelableUtil.java 0 → 100644 +47 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.shared; import android.annotation.Nullable; import android.net.LinkProperties; import android.net.ProxyInfo; /** * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties * and its attributes. * @hide */ public final class LinkPropertiesParcelableUtil { // Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable // TODO: remove the following methods after migrating clients. /** * @deprecated conversion to stable parcelable is no longer necessary. */ @Deprecated public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) { return lp; } /** * @deprecated conversion to stable parcelable is no longer necessary. */ @Deprecated public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) { return info; } }