Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d53b4053 authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Move shared packages to NetworkStack project"

parents 94b74699 1fc930c5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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",
+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));
    }
}
+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);
    }
}
+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);
    }
}
+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