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

Commit 230fabb1 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Automerger Merge Worker
Browse files

Merge changes I53ca4b98,I1757fdeb am: 3a463815

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1440767

Change-Id: If1d0eb5a1818dd7a9346f8d0d64d5f37ea1b53c2
parents 3d1cfa54 3a463815
Loading
Loading
Loading
Loading
+19 −9
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
import android.net.netlink.NetlinkSocket;
import android.net.netlink.StructNfGenMsg;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.net.util.SocketUtils;
@@ -41,11 +42,12 @@ import android.system.OsConstants;
import com.android.internal.annotations.VisibleForTesting;

import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.NoSuchElementException;

@@ -66,11 +68,12 @@ public class OffloadHardwareInterface {
    private static final String NO_IPV4_ADDRESS = "";
    private static final String NO_IPV4_GATEWAY = "";
    // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
    private static final int NF_NETLINK_CONNTRACK_NEW = 1;
    private static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
    private static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
    public static final int NF_NETLINK_CONNTRACK_NEW = 1;
    public static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
    public static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
    // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
    public static final short NFNL_SUBSYS_CTNETLINK = 1;
    public static final short IPCTNL_MSG_CT_NEW = 0;
    public static final short IPCTNL_MSG_CT_GET = 1;

    private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
@@ -237,7 +240,7 @@ public class OffloadHardwareInterface {
                NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
        if (h1 == null) return false;

        sendNetlinkMessage(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
        sendIpv4NfGenMsg(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
                           (short) (NLM_F_REQUEST | NLM_F_DUMP));

        final NativeHandle h2 = mDeps.createConntrackSocket(
@@ -267,16 +270,23 @@ public class OffloadHardwareInterface {
    }

    @VisibleForTesting
    public void sendNetlinkMessage(@NonNull NativeHandle handle, short type, short flags) {
        final int length = StructNlMsgHdr.STRUCT_SIZE;
    public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
        final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
        final byte[] msg = new byte[length];
        final StructNlMsgHdr nlh = new StructNlMsgHdr();
        final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
        byteBuffer.order(ByteOrder.nativeOrder());

        final StructNlMsgHdr nlh = new StructNlMsgHdr();
        nlh.nlmsg_len = length;
        nlh.nlmsg_type = type;
        nlh.nlmsg_flags = flags;
        nlh.nlmsg_seq = 1;
        nlh.nlmsg_seq = 0;
        nlh.pack(byteBuffer);

        // Header needs to be added to buffer since a generic netlink request is being sent.
        final StructNfGenMsg nfh = new StructNfGenMsg((byte) OsConstants.AF_INET);
        nfh.pack(byteBuffer);

        try {
            NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
                                      NETLINK_MESSAGE_TIMEOUT_MS);
+130 −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 com.android.networkstack.tethering;

import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;

import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_GET;
import static com.android.networkstack.tethering.OffloadHardwareInterface.IPCTNL_MSG_CT_NEW;
import static com.android.networkstack.tethering.OffloadHardwareInterface.NFNL_SUBSYS_CTNETLINK;
import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_DESTROY;
import static com.android.networkstack.tethering.OffloadHardwareInterface.NF_NETLINK_CONNTRACK_NEW;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.NativeHandle;
import android.system.Os;

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

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

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class ConntrackSocketTest {
    private static final long TIMEOUT = 500;

    private HandlerThread mHandlerThread;
    private Handler mHandler;
    private final SharedLog mLog = new SharedLog("privileged-test");

    private OffloadHardwareInterface mOffloadHw;
    private OffloadHardwareInterface.Dependencies mDeps;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mHandlerThread = new HandlerThread(getClass().getSimpleName());
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper());

        // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
        if (Looper.myLooper() == null) Looper.prepare();

        mDeps = new OffloadHardwareInterface.Dependencies(mLog);
        mOffloadHw = new OffloadHardwareInterface(mHandler, mLog, mDeps);
    }

    @Test
    public void testIpv4ConntrackSocket() throws Exception {
        // Set up server and connect.
        final InetSocketAddress anyAddress = new InetSocketAddress(
                InetAddress.getByName("127.0.0.1"), 0);
        final ServerSocket serverSocket = new ServerSocket();
        serverSocket.bind(anyAddress);
        final SocketAddress theAddress = serverSocket.getLocalSocketAddress();

        // Make a connection to the server.
        final Socket socket = new Socket();
        socket.connect(theAddress);
        final Socket acceptedSocket = serverSocket.accept();

        final NativeHandle handle = mDeps.createConntrackSocket(
                NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
        mOffloadHw.sendIpv4NfGenMsg(handle,
                (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
                (short) (NLM_F_REQUEST | NLM_F_DUMP));

        boolean foundConntrackEntry = false;
        ByteBuffer buffer = ByteBuffer.allocate(DEFAULT_RECV_BUFSIZE);
        buffer.order(ByteOrder.nativeOrder());

        try {
            while (Os.read(handle.getFileDescriptor(), buffer) > 0) {
                buffer.flip();

                // TODO: ConntrackMessage should get a parse API like StructNlMsgHdr
                // so we can confirm that the conntrack added is for the TCP connection above.
                final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(buffer);
                assertNotNull(nlmsghdr);

                // As long as 1 conntrack entry is found test case will pass, even if it's not
                // the from the TCP connection above.
                if (nlmsghdr.nlmsg_type == ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW)) {
                    foundConntrackEntry = true;
                    break;
                }
            }
        } finally {
            socket.close();
            serverSocket.close();
        }
        assertTrue("Did not receive any NFNL_SUBSYS_CTNETLINK/IPCTNL_MSG_CT_NEW message",
                foundConntrackEntry);
    }
}
+18 −8
Original line number Diff line number Diff line
@@ -17,8 +17,9 @@
package com.android.networkstack.tethering;

import static android.net.util.TetheringUtils.uint16;
import static android.system.OsConstants.SOCK_STREAM;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_UNIX;
import static android.system.OsConstants.SOCK_STREAM;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -35,14 +36,15 @@ import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
import android.net.netlink.StructNfGenMsg;
import android.net.netlink.StructNlMsgHdr;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.NativeHandle;
import android.os.test.TestLooper;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.system.Os;
import android.system.OsConstants;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -55,8 +57,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.io.FileDescriptor;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;

@RunWith(AndroidJUnit4.class)
@@ -218,7 +220,7 @@ public final class OffloadHardwareInterfaceTest {
    }

    @Test
    public void testNetlinkMessage() throws Exception {
    public void testSendIpv4NfGenMsg() throws Exception {
        FileDescriptor writeSocket = new FileDescriptor();
        FileDescriptor readSocket = new FileDescriptor();
        try {
@@ -229,17 +231,25 @@ public final class OffloadHardwareInterfaceTest {
        }
        when(mNativeHandle.getFileDescriptor()).thenReturn(writeSocket);

        mOffloadHw.sendNetlinkMessage(mNativeHandle, TEST_TYPE, TEST_FLAGS);
        mOffloadHw.sendIpv4NfGenMsg(mNativeHandle, TEST_TYPE, TEST_FLAGS);

        ByteBuffer buffer = ByteBuffer.allocate(9823);  // Arbitrary value > expectedLen.
        buffer.order(ByteOrder.nativeOrder());

        ByteBuffer buffer = ByteBuffer.allocate(StructNlMsgHdr.STRUCT_SIZE);
        int read = Os.read(readSocket, buffer);
        final int expectedLen = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
        assertEquals(expectedLen, read);

        buffer.flip();
        assertEquals(StructNlMsgHdr.STRUCT_SIZE, buffer.getInt());
        assertEquals(expectedLen, buffer.getInt());
        assertEquals(TEST_TYPE, buffer.getShort());
        assertEquals(TEST_FLAGS, buffer.getShort());
        assertEquals(1 /* seq */, buffer.getInt());
        assertEquals(0 /* seq */, buffer.getInt());
        assertEquals(0 /* pid */, buffer.getInt());
        assertEquals(AF_INET, buffer.get());             // nfgen_family
        assertEquals(0 /* error */, buffer.get());       // version
        assertEquals(0 /* error */, buffer.getShort());  // res_id
        assertEquals(expectedLen, buffer.position());
    }

    private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {