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

Commit 5fb020eb authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6525849 from 7bfc08f9 to rvc-release

Change-Id: I65f48a664c36ccbf01d9c6c78f81eb7ac5670e34
parents 71090361 7bfc08f9
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.util.ArrayMap;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import java.net.Inet4Address;
import java.util.ArrayList;
@@ -158,7 +159,7 @@ class DhcpLeaseRepository {
    /**
     * From a map keyed by {@link Inet4Address}, remove entries where the key is invalid (as
     * specified by {@link #isValidAddress(Inet4Address)}), or is a reserved address.
     * @return true iff at least one entry was removed.
     * @return true if and only if at least one entry was removed.
     */
    private <T> boolean cleanMap(Map<Inet4Address, T> map) {
        final Iterator<Entry<Inet4Address, T>> it = map.entrySet().iterator();
@@ -397,7 +398,8 @@ class DhcpLeaseRepository {
        mEventCallbacks.finishBroadcast();
    }

    public void markLeaseDeclined(@NonNull Inet4Address addr) {
    @VisibleForTesting
    void markLeaseDeclined(@NonNull Inet4Address addr) {
        if (mDeclinedAddrs.containsKey(addr) || !isValidAddress(addr)) {
            mLog.logf("Not marking %s as declined: already declined or not assignable",
                    inet4AddrToString(addr));
@@ -409,6 +411,22 @@ class DhcpLeaseRepository {
        maybeUpdateEarliestExpiration(expTime);
    }

    /**
     * Mark a committed lease matching the passed in clientId and hardware address parameters to be
     * declined, and delete it from the repository.
     *
     * @param clientId Client identifier option if specified, or {@link #CLIENTID_UNSPEC}
     * @param hwAddr client's mac address
     * @param Addr IPv4 address to be declined
     * @return true if a lease matching parameters was removed from committed repository.
     */
    public boolean markAndReleaseDeclinedLease(@Nullable byte[] clientId,
            @NonNull MacAddress hwAddr, @NonNull Inet4Address addr) {
        if (!releaseLease(clientId, hwAddr, addr)) return false;
        markLeaseDeclined(addr);
        return true;
    }

    /**
     * Get the list of currently valid committed leases in the repository.
     */
+158 −83
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import static java.lang.Integer.toUnsignedLong;

import android.content.Context;
import android.net.INetworkStackStatusCallback;
import android.net.IpPrefix;
import android.net.MacAddress;
import android.net.TrafficStats;
import android.net.util.NetworkStackUtils;
@@ -96,7 +97,8 @@ public class DhcpServer extends StateMachine {
    private static final int CMD_START_DHCP_SERVER = 1;
    private static final int CMD_STOP_DHCP_SERVER = 2;
    private static final int CMD_UPDATE_PARAMS = 3;
    private static final int CMD_SUSPEND_DHCP_SERVER = 4;
    @VisibleForTesting
    protected static final int CMD_RECEIVE_PACKET = 4;

    @NonNull
    private final Context mContext;
@@ -126,6 +128,8 @@ public class DhcpServer extends StateMachine {
    private final StoppedState mStoppedState = new StoppedState();
    private final StartedState mStartedState = new StartedState();
    private final RunningState mRunningState = new RunningState();
    private final WaitBeforeRetrievalState mWaitBeforeRetrievalState =
            new WaitBeforeRetrievalState();

    /**
     * Clock to be used by DhcpServer to track time for lease expiration.
@@ -262,6 +266,7 @@ public class DhcpServer extends StateMachine {
        addState(mStoppedState);
        addState(mStartedState);
            addState(mRunningState, mStartedState);
            addState(mWaitBeforeRetrievalState, mStartedState);
        // CHECKSTYLE:ON IndentationCheck

        setInitialState(mStoppedState);
@@ -372,6 +377,17 @@ public class DhcpServer extends StateMachine {
        }
    }

    private void handleUpdateServingParams(@NonNull DhcpServingParams params,
            @Nullable INetworkStackStatusCallback cb) {
        mServingParams = params;
        mLeaseRepo.updateParams(
                DhcpServingParams.makeIpPrefix(params.serverAddr),
                params.excludedAddrs,
                params.dhcpLeaseTimeSecs * 1000,
                params.singleClientAddr);
        maybeNotifyStatus(cb, STATUS_SUCCESS);
    }

    class StoppedState extends State {
        private INetworkStackStatusCallback mOnStopCallback;

@@ -422,6 +438,8 @@ public class DhcpServer extends StateMachine {
                mLeaseRepo.addLeaseCallbacks(mEventCallbacks);
            }
            maybeNotifyStatus(mOnStartCallback, STATUS_SUCCESS);
            // Clear INetworkStackStatusCallback binder token, so that it's freed
            // on the other side.
            mOnStartCallback = null;
        }

@@ -431,14 +449,7 @@ public class DhcpServer extends StateMachine {
                case CMD_UPDATE_PARAMS:
                    final Pair<DhcpServingParams, INetworkStackStatusCallback> pair =
                            (Pair<DhcpServingParams, INetworkStackStatusCallback>) msg.obj;
                    final DhcpServingParams params = pair.first;
                    mServingParams = params;
                    mLeaseRepo.updateParams(
                            DhcpServingParams.makeIpPrefix(params.serverAddr),
                            params.excludedAddrs,
                            params.dhcpLeaseTimeSecs * 1000,
                            params.singleClientAddr);
                    maybeNotifyStatus(pair.second, STATUS_SUCCESS);
                    handleUpdateServingParams(pair.first, pair.second);
                    return HANDLED;

                case CMD_START_DHCP_SERVER:
@@ -466,26 +477,19 @@ public class DhcpServer extends StateMachine {
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case CMD_SUSPEND_DHCP_SERVER:
                    // TODO: transition to the state which waits for IpServer to reconfigure the
                    // new selected prefix.
                case CMD_RECEIVE_PACKET:
                    processPacket((DhcpPacket) msg.obj);
                    return HANDLED;

                default:
                    // Fall through to StartedState.
                    return NOT_HANDLED;
            }
        }
    }

    @VisibleForTesting
    void processPacket(@NonNull DhcpPacket packet, int srcPort) {
        final String packetType = packet.getClass().getSimpleName();
        if (srcPort != DHCP_CLIENT) {
            mLog.logf("Ignored packet of type %s sent from client port %d", packetType, srcPort);
            return;
        }
        private void processPacket(@NonNull DhcpPacket packet) {
            mLog.log("Received packet of type " + packet.getClass().getSimpleName());

        mLog.log("Received packet of type " + packetType);
            final Inet4Address sid = packet.mServerIdentifier;
            if (sid != null && !sid.equals(mServingParams.serverAddr.getAddress())) {
                mLog.log("Packet ignored due to wrong server identifier: " + sid);
@@ -499,6 +503,8 @@ public class DhcpServer extends StateMachine {
                    processRequest((DhcpRequestPacket) packet);
                } else if (packet instanceof DhcpReleasePacket) {
                    processRelease((DhcpReleasePacket) packet);
                } else if (packet instanceof DhcpDeclinePacket) {
                    processDecline((DhcpDeclinePacket) packet);
                } else {
                    mLog.e("Unknown packet type: " + packet.getClass().getSimpleName());
                }
@@ -519,8 +525,8 @@ public class DhcpServer extends StateMachine {
            final MacAddress clientMac = getMacAddr(packet);
            try {
                if (mDhcpRapidCommitEnabled && packet.mRapidCommit) {
                lease = mLeaseRepo.getCommittedLease(packet.getExplicitClientIdOrNull(), clientMac,
                        packet.mRelayIp, packet.mHostName);
                    lease = mLeaseRepo.getCommittedLease(packet.getExplicitClientIdOrNull(),
                            clientMac, packet.mRelayIp, packet.mHostName);
                    transmitAck(packet, lease, clientMac);
                } else {
                    lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac,
@@ -534,7 +540,8 @@ public class DhcpServer extends StateMachine {
            }
        }

    private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException {
        private void processRequest(@NonNull DhcpRequestPacket packet)
                throws MalformedPacketException {
            // If set, packet SID matches with this server's ID as checked in processPacket().
            final boolean sidSet = packet.mServerIdentifier != null;
            final DhcpLease lease;
@@ -558,10 +565,72 @@ public class DhcpServer extends StateMachine {
                throws MalformedPacketException {
            final byte[] clientId = packet.getExplicitClientIdOrNull();
            final MacAddress macAddr = getMacAddr(packet);
        // Don't care about success (there is no ACK/NAK); logging is already done in the repository
            // Don't care about success (there is no ACK/NAK); logging is already done
            // in the repository.
            mLeaseRepo.releaseLease(clientId, macAddr, packet.mClientIp);
        }

        private void processDecline(@NonNull DhcpDeclinePacket packet)
                throws MalformedPacketException {
            final byte[] clientId = packet.getExplicitClientIdOrNull();
            final MacAddress macAddr = getMacAddr(packet);
            int committedLeasesCount = mLeaseRepo.getCommittedLeases().size();

            // If peer's clientID and macAddr doesn't match with any issued lease, nothing to do.
            if (!mLeaseRepo.markAndReleaseDeclinedLease(clientId, macAddr, packet.mRequestedIp)) {
                return;
            }

            // Check whether the boolean flag which requests a new prefix is enabled, and if
            // it's enabled, make sure the issued lease count should be only one, otherwise,
            // changing a different prefix will cause other exist host(s) configured with the
            // current prefix lose appropriate route.
            if (!mServingParams.changePrefixOnDecline || committedLeasesCount > 1) return;

            if (mEventCallbacks == null) {
                mLog.e("changePrefixOnDecline enabled but caller didn't pass a valid"
                        + "IDhcpEventCallbacks callback.");
                return;
            }

            try {
                mEventCallbacks.onNewPrefixRequest(
                        DhcpServingParams.makeIpPrefix(mServingParams.serverAddr));
                transitionTo(mWaitBeforeRetrievalState);
            } catch (RemoteException e) {
                mLog.e("could not request a new prefix to caller", e);
            }
        }
    }

    class WaitBeforeRetrievalState extends State {
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case CMD_UPDATE_PARAMS:
                    final Pair<DhcpServingParams, INetworkStackStatusCallback> pair =
                            (Pair<DhcpServingParams, INetworkStackStatusCallback>) msg.obj;
                    final IpPrefix currentPrefix =
                            DhcpServingParams.makeIpPrefix(mServingParams.serverAddr);
                    final IpPrefix newPrefix =
                            DhcpServingParams.makeIpPrefix(pair.first.serverAddr);
                    handleUpdateServingParams(pair.first, pair.second);
                    if (currentPrefix != null && !currentPrefix.equals(newPrefix)) {
                        transitionTo(mRunningState);
                    }
                    return HANDLED;

                case CMD_RECEIVE_PACKET:
                    deferMessage(msg);
                    return HANDLED;

                default:
                    // Fall through to StartedState.
                    return NOT_HANDLED;
            }
        }
    }

    private Inet4Address getAckOrOfferDst(@NonNull DhcpPacket request, @NonNull DhcpLease lease,
            boolean broadcastFlag) {
        // Unless relayed or broadcast, send to client IP if already configured on the client, or to
@@ -748,7 +817,13 @@ public class DhcpServer extends StateMachine {
        @Override
        protected void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr,
                int srcPort) {
            processPacket(packet, srcPort);
            if (srcPort != DHCP_CLIENT) {
                final String packetType = packet.getClass().getSimpleName();
                mLog.logf("Ignored packet of type %s sent from client port %d",
                        packetType, srcPort);
                return;
            }
            sendMessage(CMD_RECEIVE_PACKET, packet);
        }

        @Override
+9 −1
Original line number Diff line number Diff line
@@ -457,7 +457,7 @@ public class IpClient extends StateMachine {
    private final SharedLog mLog;
    private final LocalLog mConnectivityPacketLog;
    private final MessageHandlingLogger mMsgStateLogger;
    private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
    private final IpConnectivityLog mMetricsLog;
    private final InterfaceController mInterfaceCtrl;

    // Ignore nonzero RDNSS option lifetimes below this value. 0 = disabled.
@@ -536,6 +536,13 @@ public class IpClient extends StateMachine {
            return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name,
                    defaultValue);
        }

        /**
         * Get a IpConnectivityLog instance.
         */
        public IpConnectivityLog getIpConnectivityLog() {
            return new IpConnectivityLog();
        }
    }

    public IpClient(Context context, String ifName, IIpClientCallbacks callback,
@@ -557,6 +564,7 @@ public class IpClient extends StateMachine {
        mInterfaceName = ifName;
        mClatInterfaceName = CLAT_PREFIX + ifName;
        mDependencies = deps;
        mMetricsLog = deps.getIpConnectivityLog();
        mShutdownLatch = new CountDownLatch(1);
        mCm = mContext.getSystemService(ConnectivityManager.class);
        mObserverRegistry = observerRegistry;
+223 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.netlink;

import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
import static android.system.OsConstants.SOCK_STREAM;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assume.assumeTrue;

import android.app.Instrumentation;
import android.content.Context;
import android.net.ConnectivityManager;
import android.os.Process;
import android.system.Os;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.networkstack.apishim.common.ShimUtils;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.FileDescriptor;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class InetDiagSocketIntegrationTest {
    private ConnectivityManager mCm;
    private Context mContext;

    @Before
    public void setUp() throws Exception {
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
        mContext = instrumentation.getTargetContext();
        mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    private class Connection {
        public int socketDomain;
        public int socketType;
        public InetAddress localAddress;
        public InetAddress remoteAddress;
        public InetAddress localhostAddress;
        public InetSocketAddress local;
        public InetSocketAddress remote;
        public int protocol;
        public FileDescriptor localFd;
        public FileDescriptor remoteFd;

        public FileDescriptor createSocket() throws Exception {
            return Os.socket(socketDomain, socketType, protocol);
        }

        Connection(String to, String from) throws Exception {
            remoteAddress = InetAddress.getByName(to);
            if (from != null) {
                localAddress = InetAddress.getByName(from);
            } else {
                localAddress = (remoteAddress instanceof Inet4Address)
                        ? Inet4Address.getByName("localhost") : Inet6Address.getByName("::");
            }
            if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) {
                socketDomain = AF_INET;
                localhostAddress = Inet4Address.getByName("localhost");
            } else {
                socketDomain = AF_INET6;
                localhostAddress = Inet6Address.getByName("::");
            }
        }

        public void close() throws Exception {
            Os.close(localFd);
        }
    }

    private class TcpConnection extends Connection {
        TcpConnection(String to, String from) throws Exception {
            super(to, from);
            protocol = IPPROTO_TCP;
            socketType = SOCK_STREAM;

            remoteFd = createSocket();
            Os.bind(remoteFd, remoteAddress, 0);
            Os.listen(remoteFd, 10);
            int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort();

            localFd = createSocket();
            Os.bind(localFd, localAddress, 0);
            Os.connect(localFd, remoteAddress, remotePort);

            local = (InetSocketAddress) Os.getsockname(localFd);
            remote = (InetSocketAddress) Os.getpeername(localFd);
        }

        public void close() throws Exception {
            super.close();
            Os.close(remoteFd);
        }
    }
    private class UdpConnection extends Connection {
        UdpConnection(String to, String from) throws Exception {
            super(to, from);
            protocol = IPPROTO_UDP;
            socketType = SOCK_DGRAM;

            remoteFd = null;
            localFd = createSocket();
            Os.bind(localFd, localAddress, 0);

            Os.connect(localFd, remoteAddress, 7);
            local = (InetSocketAddress) Os.getsockname(localFd);
            remote = new InetSocketAddress(remoteAddress, 7);
        }
    }

    private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
                                         InetSocketAddress remote, boolean expectSuccess) {
        final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);

        if (expectSuccess) {
            assertEquals(Process.myUid(), uid);
        } else {
            assertNotEquals(Process.myUid(), uid);
        }
    }

    private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
        UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(),
                conn.localAddress.getHostAddress());
        final int localPort = udp.local.getPort();
        udp.close();
        return localPort;
    }

    /**
     * Create a test connection for UDP and TCP sockets and verify that this
     * {protocol, local, remote} socket result in receiving a valid UID.
     */
    public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
        TcpConnection tcp = new TcpConnection(to, from);
        checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
        checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
        checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false);
        checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
        tcp.close();

        UdpConnection udp = new UdpConnection(to, from);
        checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
        checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
        checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
                udp.remote, false);
        udp.close();
    }

    @Test
    public void testGetConnectionOwnerUid() throws Exception {
        // Skip the test for API <= Q, as b/141603906 this was only fixed in Q-QPR2
        assumeTrue(ShimUtils.isAtLeastR());
        checkGetConnectionOwnerUid("::", null);
        checkGetConnectionOwnerUid("::", "::");
        checkGetConnectionOwnerUid("0.0.0.0", null);
        checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0");
        checkGetConnectionOwnerUid("127.0.0.1", null);
        checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2");
        checkGetConnectionOwnerUid("::1", null);
        checkGetConnectionOwnerUid("::1", "::1");
    }

    /* Verify fix for b/141603906 */
    @Test
    public void testB141603906() throws Exception {
        // Skip the test for API <= Q, as b/141603906 this was only fixed in Q-QPR2
        assumeTrue(ShimUtils.isAtLeastR());
        final InetSocketAddress src = new InetSocketAddress(0);
        final InetSocketAddress dst = new InetSocketAddress(0);
        final int numThreads = 8;
        final int numSockets = 5000;
        final Thread[] threads = new Thread[numThreads];

        for (int i = 0; i < numThreads; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < numSockets; j++) {
                    mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
                }
            });
        }

        for (Thread thread : threads) {
            thread.start();
        }

        for (Thread thread : threads) {
            thread.join();
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

java_defaults {
    name: "NetworkStackTestsDefaults",
    certificate: "platform",
    platform_apis: true,
    srcs: ["src/**/*.java", "src/**/*.kt"],
    resource_dirs: ["res"],
    static_libs: [
Loading