summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp17
-rw-r--r--OWNERS1
-rw-r--r--TEST_MAPPING8
-rw-r--r--client/Android.bp25
-rw-r--r--client/NetdClientRootTest.cpp36
-rw-r--r--server/Android.bp4
-rw-r--r--server/Controllers.cpp2
-rw-r--r--server/DummyNetwork.h1
-rw-r--r--server/FirewallController.h2
-rw-r--r--server/InterfaceControllerTest.cpp5
-rw-r--r--server/IptablesBaseTest.cpp2
-rw-r--r--server/IptablesBaseTest.h4
-rw-r--r--server/IptablesRestoreController.cpp10
-rw-r--r--server/IptablesRestoreControllerTest.cpp3
-rw-r--r--server/LocalNetwork.h1
-rw-r--r--server/MDnsEventReporter.cpp1
-rw-r--r--server/MDnsEventReporter.h7
-rw-r--r--server/MDnsSdListener.cpp4
-rw-r--r--server/NFLogListenerTest.cpp3
-rw-r--r--server/NetdConstants.cpp3
-rw-r--r--server/NetdHwAidlService.cpp204
-rw-r--r--server/NetdHwAidlService.h52
-rw-r--r--server/NetdHwService.cpp7
-rw-r--r--server/NetdNativeService.cpp23
-rw-r--r--server/NetlinkHandler.cpp2
-rw-r--r--server/Network.cpp8
-rw-r--r--server/Network.h4
-rw-r--r--server/NetworkController.cpp13
-rw-r--r--server/NetworkController.h5
-rw-r--r--server/OWNERS3
-rw-r--r--server/PhysicalNetwork.cpp14
-rw-r--r--server/PhysicalNetwork.h3
-rw-r--r--server/Process.cpp2
-rw-r--r--server/RouteController.cpp36
-rw-r--r--server/RouteController.h13
-rw-r--r--server/SockDiagTest.cpp3
-rw-r--r--server/UidRanges.cpp19
-rw-r--r--server/UidRanges.h4
-rw-r--r--server/UnreachableNetwork.cpp2
-rw-r--r--server/UnreachableNetwork.h1
-rw-r--r--server/VirtualNetwork.cpp2
-rw-r--r--server/VirtualNetwork.h1
-rw-r--r--server/XfrmController.h6
-rw-r--r--server/XfrmControllerTest.cpp27
-rw-r--r--server/android.system.net.netd-service.xml7
-rw-r--r--server/main.cpp29
-rw-r--r--tests/Android.bp2
-rw-r--r--tests/benchmarks/dns_benchmark.cpp9
-rw-r--r--tests/binder_test.cpp539
-rw-r--r--tests/bpf_base_test.cpp127
-rw-r--r--tests/kernel_test.cpp2
-rw-r--r--tests/netd_test.cpp42
-rw-r--r--tests/sock_diag_test.cpp3
-rw-r--r--tests/test_utils.h21
54 files changed, 1043 insertions, 331 deletions
diff --git a/Android.bp b/Android.bp
index b654f76b..8771237d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -85,14 +85,13 @@ cc_defaults {
"-performance-noexcept-move-constructor",
"-performance-unnecessary-value-param",
],
- tidy_flags: [
- "-warnings-as-errors="
- + "android-*,"
- + "bugprone-*,"
- + "cert-*,"
- + "clang-analyzer-security*,"
- + "google-*,"
- + "misc-*,"
- + "performance-*"
+ tidy_checks_as_errors: [
+ "android-*",
+ "bugprone-*",
+ "cert-*",
+ "clang-analyzer-security*",
+ "google-*",
+ "misc-*",
+ "performance-*",
],
}
diff --git a/OWNERS b/OWNERS
index a29a33b3..39ccf1fe 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 31808
set noparent
file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4a9fa190..4e5a0471 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -3,6 +3,7 @@
{ "name": "netd_integration_test" },
{ "name": "netd_unit_test" },
{ "name": "netdclient_test" },
+ { "name": "netdclient_root_test" },
{ "name": "netdutils_test" }
],
"postsubmit": [
@@ -14,8 +15,11 @@
"imports": [
{ "path": "packages/modules/DnsResolver" }
],
- "hwasan-postsubmit": [
+ "hwasan-presubmit": [
{ "name": "netd_integration_test" },
- { "name": "netd_unit_test" }
+ { "name": "netd_unit_test" },
+ { "name": "netdclient_test" },
+ { "name": "netdclient_root_test" },
+ { "name": "netdutils_test" }
]
}
diff --git a/client/Android.bp b/client/Android.bp
index 22cb5c15..528b3548 100644
--- a/client/Android.bp
+++ b/client/Android.bp
@@ -65,3 +65,28 @@ cc_test {
recover: [ "all" ],
},
}
+
+cc_test {
+ name: "netdclient_root_test",
+ require_root: true, // for ScopedUidChange
+ srcs: [
+ "NetdClientRootTest.cpp",
+ ],
+ defaults: [
+ "netd_aidl_interface_lateststable_cpp_static",
+ "netd_defaults",
+ ],
+ test_suites: ["device-tests"],
+ include_dirs: [
+ "system/netd/include",
+ ],
+ static_libs: [
+ "libbase",
+ "libnetd_client",
+ "libnetd_test_utils",
+ ],
+ sanitize: {
+ address: false,
+ recover: [ "all" ],
+ },
+}
diff --git a/client/NetdClientRootTest.cpp b/client/NetdClientRootTest.cpp
new file mode 100644
index 00000000..3ecbcef6
--- /dev/null
+++ b/client/NetdClientRootTest.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+
+#include "NetdClient.h"
+#include "android/net/INetd.h"
+#include "netid_client.h"
+#include "test_utils.h"
+
+constexpr int TEST_UID1 = 99999;
+
+TEST(NetdClientTest, setSocketToInvalidNetwork) {
+ const android::base::unique_fd s(socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0));
+ ASSERT_LE(0, s);
+
+ unsigned netId = NETID_UNSET;
+ const ScopedUidChange scopedUidChange(TEST_UID1);
+ EXPECT_EQ(-EACCES, setNetworkForSocket(android::net::INetd::LOCAL_NET_ID, s));
+ EXPECT_EQ(0, getNetworkForSocket(&netId, s));
+ EXPECT_EQ(static_cast<unsigned>(NETID_UNSET), netId);
+}
diff --git a/server/Android.bp b/server/Android.bp
index 06ea0bab..615e740f 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -97,6 +97,7 @@ cc_binary {
"system/netd/include",
],
init_rc: ["netd.rc"],
+ vintf_fragments: ["android.system.net.netd-service.xml"],
required: [
"bpfloader",
],
@@ -104,8 +105,10 @@ cc_binary {
shared_libs: [
"android.system.net.netd@1.0",
"android.system.net.netd@1.1",
+ "android.system.net.netd-V1-ndk",
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libdl",
"libhidlbase",
@@ -138,6 +141,7 @@ cc_binary {
"MDnsSdListener.cpp",
"MDnsService.cpp",
"NetdCommand.cpp",
+ "NetdHwAidlService.cpp",
"NetdHwService.cpp",
"NetdNativeService.cpp",
"NetlinkHandler.cpp",
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 00ee186d..43a2d1ee 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -131,7 +131,7 @@ std::set<std::string> Controllers::findExistingChildChains(const IptablesTarget
std::string command = StringPrintf("*%s\n-S %s\nCOMMIT\n", table, parentChain);
std::string output;
if (Controllers::execIptablesRestoreWithOutput(target, command, &output) == -1) {
- ALOGE("Error listing chain %s in table %s\n", parentChain, table);
+ ALOGE("Error listing chain %s in table %s", parentChain, table);
return existing;
}
diff --git a/server/DummyNetwork.h b/server/DummyNetwork.h
index 8f9960b2..e699dada 100644
--- a/server/DummyNetwork.h
+++ b/server/DummyNetwork.h
@@ -25,6 +25,7 @@ class DummyNetwork : public Network {
static const char* INTERFACE_NAME;
explicit DummyNetwork(unsigned netId);
virtual ~DummyNetwork();
+ Permission getPermission() const { return PERMISSION_SYSTEM; };
private:
std::string getTypeString() const override { return "DUMMY"; };
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 6d6f48fa..1bff064c 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -52,8 +52,6 @@ public:
/* Match traffic owned by given UID. This is specific to a particular chain. */
int setUidRule(ChildChain, int, FirewallRule);
- int enableChildChains(ChildChain, bool);
-
static std::string makeCriticalCommands(IptablesTarget target, const char* chainName);
static const char* TABLE;
diff --git a/server/InterfaceControllerTest.cpp b/server/InterfaceControllerTest.cpp
index 006018d7..8075431f 100644
--- a/server/InterfaceControllerTest.cpp
+++ b/server/InterfaceControllerTest.cpp
@@ -22,6 +22,7 @@
#include <gtest/gtest.h>
#include <netdutils/MockSyscalls.h>
+#include <netdutils/NetNativeTestBase.h>
#include <netdutils/Utils.h>
#include "InterfaceController.h"
@@ -66,7 +67,7 @@ class MockProperties {
} // namespace
-class StablePrivacyTest : public testing::Test {
+class StablePrivacyTest : public NetNativeTestBase {
protected:
void expectOpenFile(const std::string& path, const Fd fd, int err) {
if (err == 0) {
@@ -179,7 +180,7 @@ TEST_F(StablePrivacyTest, ExistingPropertyWriteFail) {
EXPECT_NE(ok, enableStablePrivacyAddresses(kTestIface));
}
-class GetIfaceListTest : public testing::Test {};
+class GetIfaceListTest : public NetNativeTestBase {};
TEST_F(GetIfaceListTest, IfaceNames) {
StatusOr<std::vector<std::string>> ifaceNames = getIfaceNames();
diff --git a/server/IptablesBaseTest.cpp b/server/IptablesBaseTest.cpp
index ef4d7434..dc70ae7c 100644
--- a/server/IptablesBaseTest.cpp
+++ b/server/IptablesBaseTest.cpp
@@ -105,7 +105,7 @@ void IptablesBaseTest::expectIptablesRestoreCommands(const std::vector<std::stri
}
void IptablesBaseTest::expectIptablesRestoreCommands(const ExpectedIptablesCommands& expectedCmds) {
- EXPECT_EQ(expectedCmds.size(), sRestoreCmds.size());
+ ASSERT_EQ(expectedCmds.size(), sRestoreCmds.size());
for (size_t i = 0; i < expectedCmds.size(); i++) {
EXPECT_EQ(expectedCmds[i], sRestoreCmds[i]) <<
"iptables-restore command " << i << " differs";
diff --git a/server/IptablesBaseTest.h b/server/IptablesBaseTest.h
index abe3f84a..bfcc71a1 100644
--- a/server/IptablesBaseTest.h
+++ b/server/IptablesBaseTest.h
@@ -18,9 +18,11 @@
#include <deque>
+#include <netdutils/NetNativeTestBase.h>
+
#include "NetdConstants.h"
-class IptablesBaseTest : public ::testing::Test {
+class IptablesBaseTest : public NetNativeTestBase {
public:
IptablesBaseTest();
diff --git a/server/IptablesRestoreController.cpp b/server/IptablesRestoreController.cpp
index f7ba2008..dc718309 100644
--- a/server/IptablesRestoreController.cpp
+++ b/server/IptablesRestoreController.cpp
@@ -241,12 +241,12 @@ void IptablesRestoreController::maybeLogStderr(const std::unique_ptr<IptablesPro
return;
}
- ALOGE("iptables error:\n");
- ALOGE("------- COMMAND -------\n");
- ALOGE("%s\n", command.c_str());
- ALOGE("------- ERROR -------\n");
+ ALOGE("iptables error:");
+ ALOGE("------- COMMAND -------");
+ ALOGE("%s", command.c_str());
+ ALOGE("------- ERROR -------");
ALOGE("%s", process->errBuf.c_str());
- ALOGE("----------------------\n");
+ ALOGE("----------------------");
process->errBuf.clear();
}
diff --git a/server/IptablesRestoreControllerTest.cpp b/server/IptablesRestoreControllerTest.cpp
index a05c76d1..cecdf4d9 100644
--- a/server/IptablesRestoreControllerTest.cpp
+++ b/server/IptablesRestoreControllerTest.cpp
@@ -32,6 +32,7 @@
#include <android-base/strings.h>
#include <log/log.h>
#include <netdutils/MockSyscalls.h>
+#include <netdutils/NetNativeTestBase.h>
#include <netdutils/Stopwatch.h>
#include "NetdConstants.h"
@@ -55,7 +56,7 @@ using android::netdutils::Stopwatch;
using testing::Return;
using testing::StrictMock;
-class IptablesRestoreControllerTest : public ::testing::Test {
+class IptablesRestoreControllerTest : public NetNativeTestBase {
public:
IptablesRestoreController con;
int mDefaultMaxRetries = con.MAX_RETRIES;
diff --git a/server/LocalNetwork.h b/server/LocalNetwork.h
index c774067c..af56d245 100644
--- a/server/LocalNetwork.h
+++ b/server/LocalNetwork.h
@@ -24,6 +24,7 @@ class LocalNetwork : public Network {
public:
explicit LocalNetwork(unsigned netId);
virtual ~LocalNetwork();
+ Permission getPermission() const { return PERMISSION_SYSTEM; };
private:
std::string getTypeString() const override { return "LOCAL"; };
diff --git a/server/MDnsEventReporter.cpp b/server/MDnsEventReporter.cpp
index e94de367..92a376fe 100644
--- a/server/MDnsEventReporter.cpp
+++ b/server/MDnsEventReporter.cpp
@@ -41,7 +41,6 @@ int MDnsEventReporter::removeEventListener(const sp<IMDnsEventListener>& listene
}
const MDnsEventReporter::EventListenerSet& MDnsEventReporter::getEventListenersImpl() const {
- std::lock_guard lock(mMutex);
return mEventListeners;
}
diff --git a/server/MDnsEventReporter.h b/server/MDnsEventReporter.h
index cbc43ecb..22edbc41 100644
--- a/server/MDnsEventReporter.h
+++ b/server/MDnsEventReporter.h
@@ -51,7 +51,7 @@ class MDnsEventReporter final {
// Return registered binder services from the singleton MDnsEventReporter. This method is
// threadsafe.
- const EventListenerSet& getEventListeners() const;
+ const EventListenerSet& getEventListeners() const REQUIRES(mMutex);
// Add the binder to the singleton MDnsEventReporter. This method is threadsafe.
int addEventListener(const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener);
@@ -60,11 +60,12 @@ class MDnsEventReporter final {
int removeEventListener(
const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener);
+ mutable std::mutex mMutex;
+
private:
MDnsEventReporter() = default;
~MDnsEventReporter() = default;
- mutable std::mutex mMutex;
EventListenerSet mEventListeners GUARDED_BY(mMutex);
int addEventListenerImpl(
@@ -73,5 +74,5 @@ class MDnsEventReporter final {
int removeEventListenerImpl(
const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener)
EXCLUDES(mMutex);
- const EventListenerSet& getEventListenersImpl() const EXCLUDES(mMutex);
+ const EventListenerSet& getEventListenersImpl() const REQUIRES(mMutex);
};
diff --git a/server/MDnsSdListener.cpp b/server/MDnsSdListener.cpp
index 1d1ea40a..4bd5f0d4 100644
--- a/server/MDnsSdListener.cpp
+++ b/server/MDnsSdListener.cpp
@@ -106,6 +106,7 @@ void MDnsSdListenerDiscoverCallback(DNSServiceRef /* sdRef */, DNSServiceFlags f
const char* replyDomain, void* inContext) {
MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
int refNumber = context->mRefNumber;
+ const std::lock_guard lock(MDnsEventReporter::getInstance().mMutex);
const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
if (listeners.empty()) {
ALOGI("Discover callback not sent since no IMDnsEventListener receiver is available.");
@@ -193,6 +194,7 @@ void MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /
void* inContext) {
MDnsSdListener::Context* context = reinterpret_cast<MDnsSdListener::Context*>(inContext);
int refNumber = context->mRefNumber;
+ const std::lock_guard lock(MDnsEventReporter::getInstance().mMutex);
const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
if (listeners.empty()) {
ALOGI("Register callback not sent since no IMDnsEventListener receiver is available.");
@@ -251,6 +253,7 @@ void MDnsSdListenerResolveCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /*
void* inContext) {
MDnsSdListener::Context* context = reinterpret_cast<MDnsSdListener::Context*>(inContext);
int refNumber = context->mRefNumber;
+ const std::lock_guard lock(MDnsEventReporter::getInstance().mMutex);
const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
if (listeners.empty()) {
ALOGI("Resolve callback not sent since no IMDnsEventListener receiver is available.");
@@ -313,6 +316,7 @@ void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef /* sdRef */, DNSServiceFlag
uint32_t /* ttl */, void* inContext) {
MDnsSdListener::Context *context = reinterpret_cast<MDnsSdListener::Context *>(inContext);
int refNumber = context->mRefNumber;
+ const std::lock_guard lock(MDnsEventReporter::getInstance().mMutex);
const auto& listeners = MDnsEventReporter::getInstance().getEventListeners();
if (listeners.empty()) {
ALOGI("Get address callback not sent since no IMDnsEventListener receiver is available.");
diff --git a/server/NFLogListenerTest.cpp b/server/NFLogListenerTest.cpp
index 88ab2c61..878c9884 100644
--- a/server/NFLogListenerTest.cpp
+++ b/server/NFLogListenerTest.cpp
@@ -25,6 +25,7 @@
#include <linux/netfilter/nfnetlink_log.h>
#include <netdutils/MockSyscalls.h>
+#include <netdutils/NetNativeTestBase.h>
#include "NFLogListener.h"
using ::testing::_;
@@ -58,7 +59,7 @@ class MockNetlinkListener : public NetlinkListenerInterface {
MOCK_METHOD1(registerSkErrorHandler, void(const SkErrorHandler& handler));
};
-class NFLogListenerTest : public testing::Test {
+class NFLogListenerTest : public NetNativeTestBase {
protected:
NFLogListenerTest() {
EXPECT_CALL(*mNLListener, subscribe(kNFLogPacketMsgType, _))
diff --git a/server/NetdConstants.cpp b/server/NetdConstants.cpp
index 6de164fb..fa21f44b 100644
--- a/server/NetdConstants.cpp
+++ b/server/NetdConstants.cpp
@@ -155,8 +155,7 @@ void blockSigpipe() {
sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
- if (sigprocmask(SIG_BLOCK, &mask, nullptr) != 0)
- ALOGW("WARNING: SIGPIPE not blocked\n");
+ if (sigprocmask(SIG_BLOCK, &mask, nullptr) != 0) ALOGW("WARNING: SIGPIPE not blocked");
}
void setCloseOnExec(const char *sock) {
diff --git a/server/NetdHwAidlService.cpp b/server/NetdHwAidlService.cpp
new file mode 100644
index 00000000..42581539
--- /dev/null
+++ b/server/NetdHwAidlService.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include "NetdHwAidlService.h"
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include "Controllers.h"
+#include "Fwmark.h"
+#include "RouteController.h"
+#include "TetherController.h"
+
+// Tells TetherController::enableForwarding who is requesting forwarding, so that TetherController
+// can manage/refcount requests to enable forwarding by multiple parties such as the framework, this
+// binder interface, and the legacy "ndc ipfwd enable <requester>" commands.
+namespace {
+constexpr const char* FORWARDING_REQUESTER = "NetdHwAidlService";
+}
+
+namespace android {
+namespace net {
+namespace aidl {
+
+static int toHalStatus(int ret) {
+ switch (ret) {
+ case 0:
+ return 0;
+ case -EINVAL:
+ return NetdHwAidlService::STATUS_INVALID_ARGUMENTS;
+ case -EEXIST:
+ return NetdHwAidlService::STATUS_ALREADY_EXISTS;
+ case -ENONET:
+ return NetdHwAidlService::STATUS_NO_NETWORK;
+ case -EPERM:
+ return NetdHwAidlService::STATUS_PERMISSION_DENIED;
+ default:
+ ALOGE("HAL service error=%d", ret);
+ return NetdHwAidlService::STATUS_UNKNOWN_ERROR;
+ }
+}
+
+void NetdHwAidlService::run() {
+ std::shared_ptr<NetdHwAidlService> service = ndk::SharedRefBase::make<NetdHwAidlService>();
+
+ const std::string instance = std::string() + NetdHwAidlService::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ if (status != STATUS_OK) {
+ ALOGE("Failed to register AIDL INetd service. Status: %d.", status);
+ return;
+ }
+
+ ABinderProcess_joinThreadPool();
+}
+
+ScopedAStatus NetdHwAidlService::createOemNetwork(OemNetwork* network) {
+ unsigned netId;
+ Permission permission = PERMISSION_SYSTEM;
+
+ int ret = gCtls->netCtrl.createPhysicalOemNetwork(permission, &netId);
+
+ Fwmark fwmark;
+ fwmark.netId = netId;
+ fwmark.explicitlySelected = true;
+ fwmark.protectedFromVpn = true;
+ fwmark.permission = PERMISSION_SYSTEM;
+ network->networkHandle = netIdToNetHandle(netId);
+ network->packetMark = fwmark.intValue;
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+// Vendor code can only modify OEM networks. All other networks are managed by ConnectivityService.
+#define RETURN_IF_NOT_OEM_NETWORK(netId) \
+ if (((netId) < NetworkController::MIN_OEM_ID) || ((netId) > NetworkController::MAX_OEM_ID)) { \
+ return ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS); \
+ }
+
+ScopedAStatus NetdHwAidlService::destroyOemNetwork(int64_t netHandle) {
+ unsigned netId = netHandleToNetId(netHandle);
+ RETURN_IF_NOT_OEM_NETWORK(netId);
+
+ auto ret = toHalStatus(gCtls->netCtrl.destroyNetwork(netId));
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+const char* maybeNullString(const std::string& nexthop) {
+ // std::strings can't be null, but RouteController wants null instead of an empty string.
+ const char* nh = nexthop.c_str();
+ if (nh && !*nh) {
+ nh = nullptr;
+ }
+ return nh;
+}
+
+ScopedAStatus NetdHwAidlService::addRouteToOemNetwork(int64_t networkHandle,
+ const std::string& ifname,
+ const std::string& destination,
+ const std::string& nexthop) {
+ unsigned netId = netHandleToNetId(networkHandle);
+ RETURN_IF_NOT_OEM_NETWORK(netId);
+
+ auto ret = gCtls->netCtrl.addRoute(netId, ifname.c_str(), destination.c_str(),
+ maybeNullString(nexthop), false, INVALID_UID, 0 /* mtu */);
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+ScopedAStatus NetdHwAidlService::removeRouteFromOemNetwork(int64_t networkHandle,
+ const std::string& ifname,
+ const std::string& destination,
+ const std::string& nexthop) {
+ unsigned netId = netHandleToNetId(networkHandle);
+ RETURN_IF_NOT_OEM_NETWORK(netId);
+
+ auto ret = gCtls->netCtrl.removeRoute(netId, ifname.c_str(), destination.c_str(),
+ maybeNullString(nexthop), false, INVALID_UID);
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+ScopedAStatus NetdHwAidlService::addInterfaceToOemNetwork(int64_t networkHandle,
+ const std::string& ifname) {
+ unsigned netId = netHandleToNetId(networkHandle);
+ RETURN_IF_NOT_OEM_NETWORK(netId);
+
+ auto ret = gCtls->netCtrl.addInterfaceToNetwork(netId, ifname.c_str());
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+ScopedAStatus NetdHwAidlService::removeInterfaceFromOemNetwork(int64_t networkHandle,
+ const std::string& ifname) {
+ unsigned netId = netHandleToNetId(networkHandle);
+ RETURN_IF_NOT_OEM_NETWORK(netId);
+
+ auto ret = gCtls->netCtrl.removeInterfaceFromNetwork(netId, ifname.c_str());
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+ScopedAStatus NetdHwAidlService::setIpForwardEnable(bool enable) {
+ std::lock_guard _lock(gCtls->tetherCtrl.lock);
+
+ bool success = enable ? gCtls->tetherCtrl.enableForwarding(FORWARDING_REQUESTER)
+ : gCtls->tetherCtrl.disableForwarding(FORWARDING_REQUESTER);
+
+ if (!success) {
+ return ScopedAStatus::fromServiceSpecificError(STATUS_UNKNOWN_ERROR);
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+ScopedAStatus NetdHwAidlService::setForwardingBetweenInterfaces(const std::string& inputIfName,
+ const std::string& outputIfName,
+ bool enable) {
+ std::lock_guard _lock(gCtls->tetherCtrl.lock);
+
+ // TODO: check that one interface is an OEM interface and the other is another OEM interface, an
+ // IPsec interface or a dummy interface.
+ int ret = enable ? RouteController::enableTethering(inputIfName.c_str(), outputIfName.c_str())
+ : RouteController::disableTethering(inputIfName.c_str(), outputIfName.c_str());
+ if (ret != 0) {
+ return ScopedAStatus::fromServiceSpecificError(toHalStatus(ret));
+ } else {
+ return ScopedAStatus::ok();
+ }
+}
+
+} // namespace aidl
+} // namespace net
+} // namespace android
diff --git a/server/NetdHwAidlService.h b/server/NetdHwAidlService.h
new file mode 100644
index 00000000..5cc5b6fd
--- /dev/null
+++ b/server/NetdHwAidlService.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+#pragma once
+
+#include <aidl/android/system/net/netd/BnNetd.h>
+
+namespace android {
+namespace net {
+namespace aidl {
+using NetdHw = ::aidl::android::system::net::netd::BnNetd;
+using OemNetwork = ::aidl::android::system::net::netd::INetd::OemNetwork;
+using ScopedAStatus = ::ndk::ScopedAStatus;
+
+class NetdHwAidlService : public NetdHw {
+ public:
+ // Start and run the AIDL service.
+ // This blocks when joining the threadpool so start this in a separate thread.
+ static void run();
+ ScopedAStatus createOemNetwork(OemNetwork* network) override;
+ ScopedAStatus destroyOemNetwork(int64_t netHandle) override;
+ ScopedAStatus addRouteToOemNetwork(int64_t networkHandle, const std::string& ifname,
+ const std::string& destination,
+ const std::string& nexthop) override;
+ ScopedAStatus removeRouteFromOemNetwork(int64_t networkHandle, const std::string& ifname,
+ const std::string& destination,
+ const std::string& nexthop) override;
+ ScopedAStatus addInterfaceToOemNetwork(int64_t networkHandle,
+ const std::string& ifname) override;
+ ScopedAStatus removeInterfaceFromOemNetwork(int64_t networkHandle,
+ const std::string& ifname) override;
+ ScopedAStatus setIpForwardEnable(bool enable) override;
+ ScopedAStatus setForwardingBetweenInterfaces(const std::string& inputIfName,
+ const std::string& outputIfName,
+ bool enable) override;
+};
+
+} // namespace aidl
+} // namespace net
+} // namespace android
diff --git a/server/NetdHwService.cpp b/server/NetdHwService.cpp
index 15855da8..d4a0e58e 100644
--- a/server/NetdHwService.cpp
+++ b/server/NetdHwService.cpp
@@ -14,15 +14,13 @@
* limitations under the License.
*/
+#include "NetdHwService.h"
#include <binder/IPCThreadState.h>
-#include <hidl/HidlTransportSupport.h>
#include "Controllers.h"
#include "Fwmark.h"
-#include "NetdHwService.h"
#include "RouteController.h"
#include "TetherController.h"
-using android::hardware::configureRpcThreadpool;
using android::hardware::Void;
// Tells TetherController::enableForwarding who is requesting forwarding, so that TetherController
@@ -55,9 +53,6 @@ static StatusCode toHalStatus(int ret) {
// Minimal service start.
status_t NetdHwService::start() {
- IPCThreadState::self()->disableBackgroundScheduling(true);
- // Usage of this HAL is anticipated to be thin; one thread should suffice.
- configureRpcThreadpool(1, false /* callerWillNotJoin */);
// Register hardware service with ServiceManager.
return INetd::registerAsService();
}
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 466d8ba7..63c004d2 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -272,7 +272,8 @@ binder::Status NetdNativeService::bandwidthRemoveNiceApp(int32_t) {
// tests.
binder::Status NetdNativeService::networkCreatePhysical(int32_t netId, int32_t permission) {
ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.createPhysicalNetwork(netId, convertPermission(permission));
+ int ret = gCtls->netCtrl.createPhysicalNetwork(netId, convertPermission(permission),
+ false /* local */);
return statusFromErrcode(ret);
}
@@ -292,8 +293,11 @@ binder::Status NetdNativeService::networkCreate(const NativeNetworkConfig& confi
ENFORCE_NETWORK_STACK_PERMISSIONS();
int ret = -EINVAL;
if (config.networkType == NativeNetworkType::PHYSICAL) {
- ret = gCtls->netCtrl.createPhysicalNetwork(config.netId,
- convertPermission(config.permission));
+ ret = gCtls->netCtrl.createPhysicalNetwork(
+ config.netId, convertPermission(config.permission), false /* isLocalNetwork */);
+ } else if (config.networkType == NativeNetworkType::PHYSICAL_LOCAL) {
+ ret = gCtls->netCtrl.createPhysicalNetwork(
+ config.netId, convertPermission(config.permission), true /* isLocalNetwork */);
} else if (config.networkType == NativeNetworkType::VIRTUAL) {
ret = gCtls->netCtrl.createVirtualNetwork(config.netId, config.secure, config.vpnType,
config.excludeLocalRoutes);
@@ -664,9 +668,8 @@ binder::Status NetdNativeService::ipSecAddTunnelInterface(const std::string& dev
int32_t interfaceId) {
// Necessary locking done in IpSecService and kernel
ENFORCE_NETWORK_STACK_PERMISSIONS();
- netdutils::Status result = gCtls->xfrmCtrl.ipSecAddTunnelInterface(
- deviceName, localAddress, remoteAddress, iKey, oKey, interfaceId, false);
- return binder::Status::ok();
+ return asBinderStatus(gCtls->xfrmCtrl.ipSecAddTunnelInterface(
+ deviceName, localAddress, remoteAddress, iKey, oKey, interfaceId, false));
}
binder::Status NetdNativeService::ipSecUpdateTunnelInterface(const std::string& deviceName,
@@ -676,16 +679,14 @@ binder::Status NetdNativeService::ipSecUpdateTunnelInterface(const std::string&
int32_t interfaceId) {
// Necessary locking done in IpSecService and kernel
ENFORCE_NETWORK_STACK_PERMISSIONS();
- netdutils::Status result = gCtls->xfrmCtrl.ipSecAddTunnelInterface(
- deviceName, localAddress, remoteAddress, iKey, oKey, interfaceId, true);
- return binder::Status::ok();
+ return asBinderStatus(gCtls->xfrmCtrl.ipSecAddTunnelInterface(
+ deviceName, localAddress, remoteAddress, iKey, oKey, interfaceId, true));
}
binder::Status NetdNativeService::ipSecRemoveTunnelInterface(const std::string& deviceName) {
// Necessary locking done in IpSecService and kernel
ENFORCE_NETWORK_STACK_PERMISSIONS();
- netdutils::Status result = gCtls->xfrmCtrl.ipSecRemoveTunnelInterface(deviceName);
- return binder::Status::ok();
+ return asBinderStatus(gCtls->xfrmCtrl.ipSecRemoveTunnelInterface(deviceName));
}
binder::Status NetdNativeService::setIPv6AddrGenMode(const std::string& ifName,
diff --git a/server/NetlinkHandler.cpp b/server/NetlinkHandler.cpp
index a4e05b02..9e63a8c0 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -106,7 +106,7 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
if (!strcmp(subsys, "net")) {
NetlinkEvent::Action action = evt->getAction();
- const char *iface = evt->findParam("INTERFACE");
+ const char *iface = evt->findParam("INTERFACE") ?: "";
if (action == NetlinkEvent::Action::kAdd) {
notifyInterfaceAdded(iface);
} else if (action == NetlinkEvent::Action::kRemove) {
diff --git a/server/Network.cpp b/server/Network.cpp
index 85f942f4..156cfb3e 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -117,18 +117,12 @@ void Network::removeFromUidRangeMap(const UidRanges& uidRanges, int32_t subPrior
}
}
-bool Network::canAddUidRanges(const UidRanges& uidRanges, int32_t subPriority) const {
+bool Network::canAddUidRanges(const UidRanges& uidRanges) const {
if (uidRanges.overlapsSelf()) {
ALOGE("uid range %s overlaps self", uidRanges.toString().c_str());
return false;
}
- auto iter = mUidRangeMap.find(subPriority);
- if (iter != mUidRangeMap.end() && uidRanges.overlaps(iter->second)) {
- ALOGE("uid range %s overlaps priority %d %s", uidRanges.toString().c_str(), subPriority,
- iter->second.toString().c_str());
- return false;
- }
return true;
}
diff --git a/server/Network.h b/server/Network.h
index e18e1cdb..6c3d01d3 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -17,6 +17,7 @@
#pragma once
#include "NetdConstants.h"
+#include "Permission.h"
#include "UidRanges.h"
#include <set>
@@ -48,6 +49,7 @@ public:
std::string toString() const;
std::string uidRangesToString() const;
bool appliesToUser(uid_t uid, int32_t* subPriority) const;
+ virtual Permission getPermission() const = 0;
[[nodiscard]] virtual int addUsers(const UidRanges&, int32_t /*subPriority*/) {
return -EINVAL;
};
@@ -65,7 +67,7 @@ public:
protected:
explicit Network(unsigned netId, bool secure = false);
- bool canAddUidRanges(const UidRanges& uidRanges, int32_t subPriority) const;
+ bool canAddUidRanges(const UidRanges& uidRanges) const;
const unsigned mNetId;
std::set<std::string> mInterfaces;
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index f1441397..5233a1ea 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -382,7 +382,8 @@ bool NetworkController::isVirtualNetworkLocked(unsigned netId) const {
return network && network->isVirtual();
}
-int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission permission) {
+int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission permission,
+ bool local) {
if (!((MIN_NET_ID <= netId && netId <= MAX_NET_ID) ||
(MIN_OEM_ID <= netId && netId <= MAX_OEM_ID))) {
ALOGE("invalid netId %u", netId);
@@ -394,7 +395,7 @@ int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission pe
return -EEXIST;
}
- PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId, mDelegateImpl);
+ PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId, mDelegateImpl, local);
if (int ret = physicalNetwork->setPermission(permission)) {
ALOGE("inconceivable! setPermission cannot fail on an empty network");
delete physicalNetwork;
@@ -408,9 +409,9 @@ int NetworkController::createPhysicalNetworkLocked(unsigned netId, Permission pe
return 0;
}
-int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
+int NetworkController::createPhysicalNetwork(unsigned netId, Permission permission, bool local) {
ScopedWLock lock(mRWLock);
- return createPhysicalNetworkLocked(netId, permission);
+ return createPhysicalNetworkLocked(netId, permission, local);
}
int NetworkController::createPhysicalOemNetwork(Permission permission, unsigned *pNetId) {
@@ -431,7 +432,7 @@ int NetworkController::createPhysicalOemNetwork(Permission permission, unsigned
return -ENONET;
}
- int ret = createPhysicalNetworkLocked(*pNetId, permission);
+ int ret = createPhysicalNetworkLocked(*pNetId, permission, false /* local */);
if (ret) {
*pNetId = 0;
}
@@ -887,7 +888,7 @@ int NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) c
// Check whether the UID's permission bits are sufficient to use the network.
// Because the permission of the system default network is PERMISSION_NONE(0x0), apps can always
// pass the check here when using the system default network.
- Permission networkPermission = static_cast<PhysicalNetwork*>(network)->getPermission();
+ const Permission networkPermission = network->getPermission();
return ((userPermission & networkPermission) == networkPermission) ? 0 : -EACCES;
}
diff --git a/server/NetworkController.h b/server/NetworkController.h
index e9ef0912..d4156f98 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -105,7 +105,7 @@ public:
unsigned getNetworkForInterface(const char* interface) const;
bool isVirtualNetwork(unsigned netId) const;
- [[nodiscard]] int createPhysicalNetwork(unsigned netId, Permission permission);
+ [[nodiscard]] int createPhysicalNetwork(unsigned netId, Permission permission, bool local);
[[nodiscard]] int createPhysicalOemNetwork(Permission permission, unsigned* netId);
[[nodiscard]] int createVirtualNetwork(unsigned netId, bool secure, NativeVpnType vpnType,
bool excludeLocalRoutes);
@@ -165,7 +165,8 @@ public:
Network* getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const;
Permission getPermissionForUserLocked(uid_t uid) const;
int checkUserNetworkAccessLocked(uid_t uid, unsigned netId) const;
- [[nodiscard]] int createPhysicalNetworkLocked(unsigned netId, Permission permission);
+ [[nodiscard]] int createPhysicalNetworkLocked(unsigned netId, Permission permission,
+ bool local);
[[nodiscard]] int modifyRoute(unsigned netId, const char* interface, const char* destination,
const char* nexthop, RouteOperation op, bool legacy, uid_t uid,
diff --git a/server/OWNERS b/server/OWNERS
deleted file mode 100644
index 03fedf71..00000000
--- a/server/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 31808
-lorenzo@google.com
-maze@google.com
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index bb3f653d..923412a8 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -56,8 +56,16 @@ namespace {
PhysicalNetwork::Delegate::~Delegate() {}
-PhysicalNetwork::PhysicalNetwork(unsigned netId, PhysicalNetwork::Delegate* delegate) :
- Network(netId), mDelegate(delegate), mPermission(PERMISSION_NONE), mIsDefault(false) {
+PhysicalNetwork::PhysicalNetwork(unsigned netId, PhysicalNetwork::Delegate* delegate, bool local)
+ : Network(netId),
+ mDelegate(delegate),
+ mPermission(PERMISSION_NONE),
+ mIsDefault(false),
+ mIsLocalNetwork(local) {
+ // TODO : remove this log, it's only present to avoid -Wunused-private-field from blocking
+ // compilation
+ ALOGI("Created physical network instance netId=%d local=%s", netId,
+ mIsLocalNetwork ? "true" : "false");
}
PhysicalNetwork::~PhysicalNetwork() {}
@@ -165,7 +173,7 @@ int PhysicalNetwork::removeAsDefault() {
}
int PhysicalNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
- if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges)) {
return -EINVAL;
}
diff --git a/server/PhysicalNetwork.h b/server/PhysicalNetwork.h
index f114cca2..7166e0ea 100644
--- a/server/PhysicalNetwork.h
+++ b/server/PhysicalNetwork.h
@@ -33,7 +33,7 @@ class PhysicalNetwork : public Network {
Permission permission) = 0;
};
- PhysicalNetwork(unsigned netId, Delegate* delegate);
+ PhysicalNetwork(unsigned netId, Delegate* delegate, bool local);
virtual ~PhysicalNetwork();
// These refer to permissions that apps must have in order to use this network.
@@ -58,6 +58,7 @@ class PhysicalNetwork : public Network {
Delegate* const mDelegate;
Permission mPermission;
bool mIsDefault;
+ const bool mIsLocalNetwork;
};
} // namespace android::net
diff --git a/server/Process.cpp b/server/Process.cpp
index f43e82dc..fa14587a 100644
--- a/server/Process.cpp
+++ b/server/Process.cpp
@@ -85,7 +85,7 @@ void blockSigPipe() {
sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
if (sigprocmask(SIG_BLOCK, &mask, nullptr) != 0) {
- ALOGW("WARNING: SIGPIPE not blocked\n");
+ ALOGW("WARNING: SIGPIPE not blocked");
}
}
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index d2af9a37..86b23b6d 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -64,7 +64,7 @@ const char* const ROUTE_TABLE_NAME_MAIN = "main";
const char* const RouteController::LOCAL_MANGLE_INPUT = "routectrl_mangle_INPUT";
-const IPPrefix V4_LOCAL_ADDR[] = {
+const IPPrefix V4_LOCAL_PREFIXES[] = {
IPPrefix::forString("169.254.0.0/16"), // Link Local
IPPrefix::forString("100.64.0.0/10"), // CGNAT
IPPrefix::forString("10.0.0.0/8"), // RFC1918
@@ -667,6 +667,19 @@ int RouteController::modifyVpnLocalExclusionRule(bool add, const char* physicalI
INVALID_UID);
}
+int RouteController::addFixedLocalRoutes(const char* interface) {
+ for (size_t i = 0; i < ARRAY_SIZE(V4_FIXED_LOCAL_PREFIXES); ++i) {
+ if (int ret = modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface,
+ V4_FIXED_LOCAL_PREFIXES[i], nullptr /* nexthop */,
+ RouteController::INTERFACE, 0 /* mtu */, 0 /* priority */,
+ true /* isLocal */)) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
// A rule to enable split tunnel VPNs.
//
// If a packet with a VPN's netId doesn't find a route in the VPN's routing table, it's allowed to
@@ -1297,6 +1310,11 @@ int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* i
maybeModifyQdiscClsact(interface, ACTION_ADD);
updateTableNamesFile();
+
+ if (int ret = addFixedLocalRoutes(interface)) {
+ return ret;
+ }
+
return 0;
}
@@ -1392,8 +1410,8 @@ int RouteController::removeInterfaceFromDefaultNetwork(const char* interface,
return modifyDefaultNetwork(RTM_DELRULE, interface, permission);
}
-bool RouteController::isTargetV4LocalRange(const char* dst) {
- for (IPPrefix addr : V4_LOCAL_ADDR) {
+bool RouteController::isWithinIpv4LocalPrefix(const char* dst) {
+ for (IPPrefix addr : V4_LOCAL_PREFIXES) {
if (addr.contains(IPPrefix::forString(dst))) {
return true;
}
@@ -1401,14 +1419,14 @@ bool RouteController::isTargetV4LocalRange(const char* dst) {
return false;
}
-bool RouteController::isLocalAddress(TableType tableType, const char* destination,
- const char* nexthop) {
+bool RouteController::isLocalRoute(TableType tableType, const char* destination,
+ const char* nexthop) {
IPPrefix prefix = IPPrefix::forString(destination);
return nexthop == nullptr && tableType == RouteController::INTERFACE &&
// Skip default route to prevent network being modeled as point-to-point interfaces.
((prefix.family() == AF_INET6 && prefix != IPPrefix::forString("::/0")) ||
// Skip adding non-target local network range.
- (prefix.family() == AF_INET && isTargetV4LocalRange(destination)));
+ (prefix.family() == AF_INET && isWithinIpv4LocalPrefix(destination)));
}
int RouteController::addRoute(const char* interface, const char* destination, const char* nexthop,
@@ -1418,7 +1436,7 @@ int RouteController::addRoute(const char* interface, const char* destination, co
return ret;
}
- if (isLocalAddress(tableType, destination, nexthop)) {
+ if (isLocalRoute(tableType, destination, nexthop)) {
return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination,
nexthop, tableType, mtu, priority, true /* isLocal */);
}
@@ -1433,7 +1451,7 @@ int RouteController::removeRoute(const char* interface, const char* destination,
return ret;
}
- if (isLocalAddress(tableType, destination, nexthop)) {
+ if (isLocalRoute(tableType, destination, nexthop)) {
return modifyRoute(RTM_DELROUTE, NETLINK_REQUEST_FLAGS, interface, destination, nexthop,
tableType, 0 /* mtu */, priority, true /* isLocal */);
}
@@ -1447,7 +1465,7 @@ int RouteController::updateRoute(const char* interface, const char* destination,
return ret;
}
- if (isLocalAddress(tableType, destination, nexthop)) {
+ if (isLocalRoute(tableType, destination, nexthop)) {
return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_REPLACE_FLAGS, interface, destination,
nexthop, tableType, mtu, 0 /* priority */, true /* isLocal */);
}
diff --git a/server/RouteController.h b/server/RouteController.h
index ff41678d..0d4e2b96 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -198,6 +198,14 @@ public:
private:
friend class RouteControllerTest;
+ // An expandable array for fixed local prefix though it's only one element now.
+ static constexpr const char* V4_FIXED_LOCAL_PREFIXES[] = {
+ // The multicast range is 224.0.0.0/4 but only limit it to 224.0.0.0/24 since the IPv4
+ // definitions are not as precise as for IPv6, it is the only range that the standards
+ // (RFC 2365 and RFC 5771) specify is link-local and must not be forwarded.
+ "224.0.0.0/24" // Link-local multicast; non-internet routable
+ };
+
static std::mutex sInterfaceToTableLock;
static std::map<std::string, uint32_t> sInterfaceToTable GUARDED_BY(sInterfaceToTableLock);
@@ -230,8 +238,9 @@ public:
static int modifyUidLocalNetworkRule(const char* interface, uid_t uidStart, uid_t uidEnd,
bool add);
- static bool isLocalAddress(TableType tableType, const char* destination, const char* nexthop);
- static bool isTargetV4LocalRange(const char* addrstr);
+ static bool isLocalRoute(TableType tableType, const char* destination, const char* nexthop);
+ static bool isWithinIpv4LocalPrefix(const char* addrstr);
+ static int addFixedLocalRoutes(const char* interface);
};
// Public because they are called by by RouteControllerTest.cpp.
diff --git a/server/SockDiagTest.cpp b/server/SockDiagTest.cpp
index 49601aa4..864d08d5 100644
--- a/server/SockDiagTest.cpp
+++ b/server/SockDiagTest.cpp
@@ -24,6 +24,7 @@
#include <linux/inet_diag.h>
#include <gtest/gtest.h>
+#include <netdutils/NetNativeTestBase.h>
#include "Fwmark.h"
#include "NetdConstants.h"
@@ -33,7 +34,7 @@
namespace android {
namespace net {
-class SockDiagTest : public ::testing::Test {
+class SockDiagTest : public NetNativeTestBase {
protected:
static bool isLoopbackSocket(const inet_diag_msg *msg) {
return SockDiag::isLoopbackSocket(msg);
diff --git a/server/UidRanges.cpp b/server/UidRanges.cpp
index c90f30b9..765df322 100644
--- a/server/UidRanges.cpp
+++ b/server/UidRanges.cpp
@@ -145,25 +145,6 @@ bool UidRanges::overlapsSelf() const {
return false;
}
-// std::binary_search cannot do partial match. For example, an uid range x-y not only overlaps with
-// x-y, but also w-x, y-z, w-z, ...etc. Therefore, we need a specialized binary search.
-bool UidRanges::overlaps(const UidRanges& other) const {
- for (const auto& target : other.getRanges()) {
- int first = 0;
- int end = mRanges.size() - 1;
-
- while (first <= end) {
- int middle = (first + end) / 2;
- if (isOverlapped(mRanges[middle], target)) return true;
- if (compUidRangeParcel(mRanges[middle], target))
- first = middle + 1;
- else
- end = middle - 1;
- }
- }
- return false;
-}
-
std::string UidRanges::toString() const {
std::string s("uids{ ");
for (const auto &range : mRanges) {
diff --git a/server/UidRanges.h b/server/UidRanges.h
index 9123eb17..f20dc443 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -51,12 +51,10 @@ public:
// check if 'mRanges' has uid overlap between elements.
bool overlapsSelf() const;
- // check if this object has uid overlap with the input object.
- bool overlaps(const UidRanges& other) const;
+
bool empty() const { return mRanges.empty(); }
private:
- // Keep it sorted. The overlaps() implements binary search, which requires a sorted data.
std::vector<UidRangeParcel> mRanges;
};
diff --git a/server/UnreachableNetwork.cpp b/server/UnreachableNetwork.cpp
index 68802251..dd6318c0 100644
--- a/server/UnreachableNetwork.cpp
+++ b/server/UnreachableNetwork.cpp
@@ -27,7 +27,7 @@ namespace net {
UnreachableNetwork::UnreachableNetwork(unsigned netId) : Network(netId) {}
int UnreachableNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
- if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges)) {
return -EINVAL;
}
diff --git a/server/UnreachableNetwork.h b/server/UnreachableNetwork.h
index d2cefde6..0ffc0ce8 100644
--- a/server/UnreachableNetwork.h
+++ b/server/UnreachableNetwork.h
@@ -23,6 +23,7 @@ namespace android::net {
class UnreachableNetwork : public Network {
public:
explicit UnreachableNetwork(unsigned netId);
+ Permission getPermission() const { return PERMISSION_SYSTEM; };
[[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
[[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
bool isUnreachable() override { return true; }
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 495fd161..e0f60407 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -33,7 +33,7 @@ VirtualNetwork::VirtualNetwork(unsigned netId, bool secure, bool excludeLocalRou
VirtualNetwork::~VirtualNetwork() {}
int VirtualNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
- if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges)) {
return -EINVAL;
}
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index 63bc5891..6e9bdadb 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -35,6 +35,7 @@ class VirtualNetwork : public Network {
public:
explicit VirtualNetwork(unsigned netId, bool secure, bool excludeLocalRoutes = false);
virtual ~VirtualNetwork();
+ Permission getPermission() const { return PERMISSION_SYSTEM; };
[[nodiscard]] int addUsers(const UidRanges& uidRanges, int32_t subPriority) override;
[[nodiscard]] int removeUsers(const UidRanges& uidRanges, int32_t subPriority) override;
bool isVirtual() override { return true; }
diff --git a/server/XfrmController.h b/server/XfrmController.h
index 4f167c5f..6da0c68a 100644
--- a/server/XfrmController.h
+++ b/server/XfrmController.h
@@ -286,6 +286,10 @@ public:
// Exposed for testing
static constexpr size_t MAX_KEY_LENGTH = 128;
+ // Disable this warning since avoiding it makes the code unreadable.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+
// Container for the content of an XFRMA_ALG_CRYPT netlink attribute.
// Exposed for testing
struct nlattr_algo_crypt {
@@ -310,6 +314,8 @@ public:
uint8_t key[MAX_KEY_LENGTH];
};
+#pragma clang diagnostic pop
+
// Exposed for testing
struct nlattr_user_tmpl {
nlattr hdr;
diff --git a/server/XfrmControllerTest.cpp b/server/XfrmControllerTest.cpp
index e7f5cfc0..9328c14b 100644
--- a/server/XfrmControllerTest.cpp
+++ b/server/XfrmControllerTest.cpp
@@ -41,6 +41,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
+#include <netdutils/NetNativeTestBase.h>
#include "Fwmark.h"
#include "NetdConstants.h"
@@ -127,7 +128,7 @@ void expectAddressEquals(int family, const std::string& expected, const xfrm_add
EXPECT_EQ(expected, actualStr);
}
-class XfrmControllerTest : public ::testing::Test {
+class XfrmControllerTest : public NetNativeTestBase {
public:
testing::StrictMock<netdutils::ScopedMockSyscalls> mockSyscalls;
};
@@ -389,8 +390,12 @@ void testIpSecAddSecurityAssociation(testCaseParams params, const MockSyscalls&
Slice attr_buf = drop(nlMsgSlice, NLA_ALIGN(sizeof(xfrm_usersa_info)));
// Extract and check the encryption/authentication algorithm
- XfrmController::nlattr_algo_crypt encryptAlgo{};
- XfrmController::nlattr_algo_auth authAlgo{};
+ XfrmController::nlattr_algo_crypt _encryptAlgo{};
+ XfrmController::nlattr_algo_auth _authAlgo{};
+ // Need to use a pointer since you can't pass a structure with a variable
+ // sized array in a lambda.
+ XfrmController::nlattr_algo_crypt* const encryptAlgo = &_encryptAlgo;
+ XfrmController::nlattr_algo_auth* const authAlgo = &_authAlgo;
XfrmController::nlattr_xfrm_mark mark{};
XfrmController::nlattr_xfrm_output_mark outputmark{};
XfrmController::nlattr_xfrm_interface_id xfrm_if_id{};
@@ -398,15 +403,15 @@ void testIpSecAddSecurityAssociation(testCaseParams params, const MockSyscalls&
const nlattr& attr, const Slice& attr_payload) {
Slice buf = attr_payload;
if (attr.nla_type == XFRMA_ALG_CRYPT) {
- encryptAlgo.hdr = attr;
- netdutils::extract(buf, encryptAlgo.crypt);
+ encryptAlgo->hdr = attr;
+ netdutils::extract(buf, encryptAlgo->crypt);
buf = drop(buf, sizeof(xfrm_algo));
- netdutils::extract(buf, encryptAlgo.key);
+ netdutils::extract(buf, encryptAlgo->key);
} else if (attr.nla_type == XFRMA_ALG_AUTH_TRUNC) {
- authAlgo.hdr = attr;
- netdutils::extract(buf, authAlgo.auth);
+ authAlgo->hdr = attr;
+ netdutils::extract(buf, authAlgo->auth);
buf = drop(buf, sizeof(xfrm_algo_auth));
- netdutils::extract(buf, authAlgo.key);
+ netdutils::extract(buf, authAlgo->key);
} else if (attr.nla_type == XFRMA_MARK) {
mark.hdr = attr;
netdutils::extract(buf, mark.mark);
@@ -424,9 +429,9 @@ void testIpSecAddSecurityAssociation(testCaseParams params, const MockSyscalls&
// TODO: Use ContainerEq or ElementsAreArray to get better test failure messages.
EXPECT_EQ(0, memcmp(reinterpret_cast<void*>(cryptKey.data()),
- reinterpret_cast<void*>(&encryptAlgo.key), KEY_LENGTH));
+ reinterpret_cast<void*>(&encryptAlgo->key), KEY_LENGTH));
EXPECT_EQ(0, memcmp(reinterpret_cast<void*>(authKey.data()),
- reinterpret_cast<void*>(&authAlgo.key), KEY_LENGTH));
+ reinterpret_cast<void*>(&authAlgo->key), KEY_LENGTH));
if (mode == XfrmMode::TUNNEL) {
if (params.xfrmInterfacesEnabled) {
diff --git a/server/android.system.net.netd-service.xml b/server/android.system.net.netd-service.xml
new file mode 100644
index 00000000..7152da19
--- /dev/null
+++ b/server/android.system.net.netd-service.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="framework">
+ <hal format="aidl">
+ <name>android.system.net.netd</name>
+ <version>1</version>
+ <fqname>INetd/default</fqname>
+ </hal>
+</manifest>
diff --git a/server/main.cpp b/server/main.cpp
index 0e81d4e5..35c53de7 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -32,8 +32,11 @@
#include "log/log.h"
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <hidl/HidlTransportSupport.h>
#include <netdutils/Stopwatch.h>
#include <processgroup/processgroup.h>
@@ -43,6 +46,7 @@
#include "MDnsService.h"
#include "NFLogListener.h"
#include "NetdConstants.h"
+#include "NetdHwAidlService.h"
#include "NetdHwService.h"
#include "NetdNativeService.h"
#include "NetlinkManager.h"
@@ -64,6 +68,7 @@ using android::net::NetdHwService;
using android::net::NetdNativeService;
using android::net::NetlinkManager;
using android::net::NFLogListener;
+using android::net::aidl::NetdHwAidlService;
using android::netdutils::Stopwatch;
const char* const PID_FILE_PATH = "/data/misc/net/netd_pid";
@@ -162,8 +167,8 @@ int main() {
}
logListener = std::move(result.value());
auto status = gCtls->wakeupCtrl.init(logListener.get());
- if (!isOk(result)) {
- gLog.error("Unable to init WakeupController: %s", toString(result).c_str());
+ if (!isOk(status)) {
+ gLog.error("Unable to init WakeupController: %s", toString(status).c_str());
// We can still continue without wakeup packet logging.
}
}
@@ -202,16 +207,26 @@ int main() {
android::net::process::ScopedPidFile pidFile(PID_FILE_PATH);
// Now that netd is ready to process commands, advertise service availability for HAL clients.
+ // Usage of this HAL is anticipated to be thin; one thread per HAL service should suffice,
+ // AIDL and HIDL.
+ android::hardware::configureRpcThreadpool(2, true /* callerWillJoin */);
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+
+ std::thread aidlService = std::thread(NetdHwAidlService::run);
+
sp<NetdHwService> mHwSvc(new NetdHwService());
+ bool startedHidlService = true;
if ((ret = mHwSvc->start()) != android::OK) {
- ALOGE("Unable to start NetdHwService: %d", ret);
- exit(1);
+ ALOGE("Unable to start HIDL NetdHwService: %d", ret);
+ startedHidlService = false;
}
+
gLog.info("Registering NetdHwService: %" PRId64 "us", subTime.getTimeAndResetUs());
gLog.info("Netd started in %" PRId64 "us", s.timeTakenUs());
-
- IPCThreadState::self()->joinThreadPool();
-
+ if (startedHidlService) {
+ IPCThreadState::self()->joinThreadPool();
+ }
+ aidlService.join();
gLog.info("netd exiting");
exit(0);
diff --git a/tests/Android.bp b/tests/Android.bp
index ff918cc1..f590f768 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -75,6 +75,7 @@ cc_test {
"device-tests",
"vts"
],
+ isolated: false,
require_root: true,
defaults: [
"netd_aidl_interface_lateststable_cpp_static",
@@ -84,7 +85,6 @@ cc_test {
srcs: [
":netd_integration_test_shared",
"binder_test.cpp",
- "bpf_base_test.cpp",
"kernel_test.cpp",
"netd_client_test.cpp",
"netd_test.cpp",
diff --git a/tests/benchmarks/dns_benchmark.cpp b/tests/benchmarks/dns_benchmark.cpp
index b8f626e9..060e40a9 100644
--- a/tests/benchmarks/dns_benchmark.cpp
+++ b/tests/benchmarks/dns_benchmark.cpp
@@ -65,11 +65,12 @@ public:
std::vector<std::string> domains = { "example.com" };
std::vector<std::string> servers;
dns.SetupMappings(num_hosts, domains, &mappings);
-
dns.SetupDNSServers(MAXNS, mappings, &mDns, &servers);
-
- const std::vector<int> mDefaultParams_Binder = {300, 25, 8, 8, 1000};
- dns.SetResolversForNetwork(servers, domains, mDefaultParams_Binder);
+ dns.SetResolversFromParcel(ResolverParams::Builder()
+ .setDnsServers(servers)
+ .setDotServers({})
+ .setDomains(domains)
+ .build());
}
}
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index bc1e7393..33a9d69f 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -50,6 +50,7 @@
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/test_utils.h>
#include <android/multinetwork.h>
#include <binder/IPCThreadState.h>
#include <bpf/BpfMap.h>
@@ -58,6 +59,7 @@
#include <com/android/internal/net/IOemNetd.h>
#include <cutils/multiuser.h>
#include <gtest/gtest.h>
+#include <netdutils/NetNativeTestBase.h>
#include <netutils/ifc.h>
#include <utils/Errors.h>
#include "Fwmark.h"
@@ -144,6 +146,7 @@ using android::net::mdns::aidl::ResolutionInfo;
using android::net::netd::aidl::NativeUidRangeConfig;
using android::netdutils::getIfaceNames;
using android::netdutils::IPAddress;
+using android::netdutils::IPSockAddr;
using android::netdutils::ScopedAddrinfo;
using android::netdutils::sSyscalls;
using android::netdutils::Stopwatch;
@@ -175,7 +178,7 @@ static const in6_addr V6_ADDR = {
{// 2001:db8:cafe::8888
.u6_addr8 = {0x20, 0x01, 0x0d, 0xb8, 0xca, 0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88}}};
-class NetdBinderTest : public ::testing::Test {
+class NetdBinderTest : public NetNativeTestBase {
public:
NetdBinderTest() {
sp<IServiceManager> sm = android::defaultServiceManager();
@@ -243,6 +246,13 @@ class NetdBinderTest : public ::testing::Test {
int vpnNetId, bool secure,
std::vector<UidRangeParcel>&& appDefaultUidRanges,
std::vector<UidRangeParcel>&& vpnUidRanges);
+
+ void setupNetworkRoutesForVpnAndDefaultNetworks(
+ int systemDefaultNetId, int appDefaultNetId, int vpnNetId, int otherNetId, bool secure,
+ bool testV6, bool differentLocalRoutes,
+ std::vector<UidRangeParcel>&& appDefaultUidRanges,
+ std::vector<UidRangeParcel>&& vpnUidRanges);
+
protected:
// Use -1 to represent that default network was not modified because
// real netId must be an unsigned value.
@@ -637,7 +647,7 @@ NativeUidRangeConfig makeNativeUidRangeConfig(unsigned netId, std::vector<UidRan
int32_t subPriority) {
NativeUidRangeConfig res;
res.netId = netId;
- res.uidRanges = move(uidRanges);
+ res.uidRanges = std::move(uidRanges);
res.subPriority = subPriority;
return res;
@@ -1233,7 +1243,7 @@ TEST_F(NetdBinderTest, TetherGetStats) {
for (const auto& path : { IPTABLES_PATH, IP6TABLES_PATH }) {
delTetherCounterValues(path, intIface1, extIface1);
delTetherCounterValues(path, intIface2, extIface2);
- if (path == IP6TABLES_PATH) {
+ if (strcmp(path, IP6TABLES_PATH) == 0) {
delTetherCounterValues(path, intIface3, extIface2);
}
}
@@ -1678,6 +1688,10 @@ TEST_F(NetdBinderTest, NetworkAddRemoveRouteToLocalExcludeTable) {
{IP_RULE_V6, "2001:db8::/32", ""},
};
+ // This should ba aligned with V4_FIXED_LOCAL_PREFIXES in system/netd/server/RouteController.cpp
+ // An expandable array for fixed local prefix though it's only one element now.
+ static const char* kV4LocalPrefixes[] = {"224.0.0.0/24"};
+
// Add test physical network
const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
INetd::PERMISSION_NONE, false, false);
@@ -1692,6 +1706,13 @@ TEST_F(NetdBinderTest, NetworkAddRemoveRouteToLocalExcludeTable) {
EXPECT_TRUE(mNetd->networkSetDefault(TEST_NETID1).isOk());
std::string localTableName = std::string(sTun.name() + "_local");
+
+ // Verify the fixed routes exist in the local table.
+ for (size_t i = 0; i < std::size(kV4LocalPrefixes); i++) {
+ expectNetworkRouteExists(IP_RULE_V4, sTun.name(), kV4LocalPrefixes[i], "",
+ localTableName.c_str());
+ }
+
// Set up link-local routes for connectivity to the "gateway"
for (size_t i = 0; i < std::size(kDirectlyConnectedRoutes); i++) {
const auto& td = kDirectlyConnectedRoutes[i];
@@ -2460,6 +2481,13 @@ TEST_F(NetdBinderTest, TetherInterfaceAddRemoveList) {
status = mNetd->tetherInterfaceList(&ifList);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
expectTetherInterfaceNotExists(ifList, sTun.name());
+
+ // Disable IPv6 tethering will disable IPv6 abilities by changing IPv6 settings(accept_ra,
+ // dad_transmits, accept_dad, disable_ipv6). See tetherInterfaceRemove in details.
+ // Re-init sTun to reset the interface to prevent affecting other test that requires IPv6 with
+ // the same interface.
+ sTun.destroy();
+ sTun.init();
}
TEST_F(NetdBinderTest, TetherDnsSetList) {
@@ -3042,6 +3070,7 @@ TEST_F(NetdBinderTest, InterfaceSetEnableIPv6) {
}
TEST_F(NetdBinderTest, InterfaceSetMtu) {
+ const int currentMtu = getInterfaceMtu(sTun.name());
const int testMtu = 1200;
// Add test physical network
@@ -3054,6 +3083,10 @@ TEST_F(NetdBinderTest, InterfaceSetMtu) {
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
expectInterfaceMtu(sTun.name(), testMtu);
+ // restore the MTU back
+ status = mNetd->interfaceSetMtu(sTun.name(), currentMtu);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
// Remove test physical network
EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk());
}
@@ -3486,23 +3519,6 @@ void NetdBinderTest::createVpnAndAppDefaultNetworkWithUid(
namespace {
-class ScopedUidChange {
- public:
- explicit ScopedUidChange(uid_t uid) : mInputUid(uid) {
- mStoredUid = geteuid();
- if (mInputUid == mStoredUid) return;
- EXPECT_TRUE(seteuid(uid) == 0);
- }
- ~ScopedUidChange() {
- if (mInputUid == mStoredUid) return;
- EXPECT_TRUE(seteuid(mStoredUid) == 0);
- }
-
- private:
- uid_t mInputUid;
- uid_t mStoredUid;
-};
-
void clearQueue(int tunFd) {
char buf[4096];
int ret;
@@ -3521,34 +3537,53 @@ void checkDataReceived(int udpSocket, int tunFd, sockaddr* dstAddr, int addrLen)
EXPECT_GT(read(tunFd, buf, sizeof(buf)), 0);
}
-bool sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, int tunFd,
- bool doConnect = true) {
+bool sendPacketFromUid(uid_t uid, IPSockAddr& dstAddr, Fwmark* fwmark, int tunFd,
+ bool doConnect = true) {
+ int family = dstAddr.family();
ScopedUidChange scopedUidChange(uid);
- unique_fd testSocket(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- if (testSocket < 0) return false;
+ unique_fd testSocket(socket(family, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- const sockaddr_in6 dst6 = {
- .sin6_family = AF_INET6,
- .sin6_port = 42,
- .sin6_addr = dstAddr,
- };
- if (doConnect && connect(testSocket, (sockaddr*)&dst6, sizeof(dst6)) == -1) return false;
+ if (testSocket < 0) return false;
+ const sockaddr_storage dst = IPSockAddr(dstAddr.ip(), dstAddr.port());
+ if (doConnect && connect(testSocket, (sockaddr*)&dst, sizeof(dst)) == -1) return false;
socklen_t fwmarkLen = sizeof(fwmark->intValue);
EXPECT_NE(-1, getsockopt(testSocket, SOL_SOCKET, SO_MARK, &(fwmark->intValue), &fwmarkLen));
- char addr[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, &dstAddr, addr, INET6_ADDRSTRLEN);
- SCOPED_TRACE(StringPrintf("sendIPv6Packet, addr: %s, uid: %u, doConnect: %s", addr, uid,
+ int addr_len = (family == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
+ char addr[addr_len];
+ inet_ntop(family, &dstAddr, addr, addr_len);
+ SCOPED_TRACE(StringPrintf("sendPacket, addr: %s, uid: %u, doConnect: %s", addr, uid,
doConnect ? "true" : "false"));
if (doConnect) {
checkDataReceived(testSocket, tunFd, nullptr, 0);
} else {
- checkDataReceived(testSocket, tunFd, (sockaddr*)&dst6, sizeof(dst6));
+ checkDataReceived(testSocket, tunFd, (sockaddr*)&dst, sizeof(dst));
}
+
return true;
}
+bool sendIPv4PacketFromUid(uid_t uid, const in_addr& dstAddr, Fwmark* fwmark, int tunFd,
+ bool doConnect = true) {
+ const sockaddr_in dst = {.sin_family = AF_INET, .sin_port = 42, .sin_addr = dstAddr};
+ IPSockAddr addr = IPSockAddr(dst);
+
+ return sendPacketFromUid(uid, addr, fwmark, tunFd, doConnect);
+}
+
+bool sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, int tunFd,
+ bool doConnect = true) {
+ const sockaddr_in6 dst6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = 42,
+ .sin6_addr = dstAddr,
+ };
+ IPSockAddr addr = IPSockAddr(dst6);
+
+ return sendPacketFromUid(uid, addr, fwmark, tunFd, doConnect);
+}
+
// Send an IPv6 packet from the uid. Expect to fail and get specified errno.
bool sendIPv6PacketFromUidFail(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, bool doConnect,
int expectedErr) {
@@ -3893,7 +3928,7 @@ void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRange
void verifyAppUidRules(std::vector<bool>&& expectedResults, NativeUidRangeConfig& uidRangeConfig,
const std::string& iface) {
- verifyAppUidRules(move(expectedResults), uidRangeConfig.uidRanges, iface,
+ verifyAppUidRules(std::move(expectedResults), uidRangeConfig.uidRanges, iface,
uidRangeConfig.subPriority);
}
@@ -3982,7 +4017,7 @@ void expectUnreachableError(uid_t uid, unsigned netId, int selectionMode) {
} // namespace
-// Verify whether API reject overlapped UID ranges
+// Verify how the API handle overlapped UID ranges
TEST_F(NetdBinderTest, PerAppDefaultNetwork_OverlappedUidRanges) {
const auto& config = makeNativeNetworkConfig(APP_DEFAULT_NETID, NativeNetworkType::PHYSICAL,
INetd::PERMISSION_NONE, false, false);
@@ -3996,28 +4031,23 @@ TEST_F(NetdBinderTest, PerAppDefaultNetwork_OverlappedUidRanges) {
binder::Status status;
status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
{makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+ EXPECT_TRUE(status.isOk());
status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
{makeUidRangeParcel(BASE_UID + 9, BASE_UID + 10)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+ EXPECT_TRUE(status.isOk());
status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
{makeUidRangeParcel(BASE_UID + 11, BASE_UID + 11)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+ EXPECT_TRUE(status.isOk());
status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
{makeUidRangeParcel(BASE_UID + 12, BASE_UID + 13)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+ EXPECT_TRUE(status.isOk());
status = mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
{makeUidRangeParcel(BASE_UID + 9, BASE_UID + 13)});
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+ EXPECT_TRUE(status.isOk());
std::vector<UidRangeParcel> selfOverlappedUidRanges = {
makeUidRangeParcel(BASE_UID + 20, BASE_UID + 20),
@@ -4356,6 +4386,311 @@ TEST_P(VpnParameterizedTest, UnconnectedSocket) {
expectPacketSentOnNetId(TEST_UID2, NETID_UNSET, vpnFd, UNCONNECTED_SOCKET);
}
+class VpnLocalRoutesParameterizedTest
+ : public NetdBinderTest,
+ public testing::WithParamInterface<std::tuple<int, int, bool, bool, bool, bool>> {
+ protected:
+ // Local/non-local addresses based on the route added in
+ // setupNetworkRoutesForVpnAndDefaultNetworks.
+ in_addr V4_LOCAL_ADDR = {htonl(0xC0A80008)}; // 192.168.0.8
+ in_addr V4_APP_LOCAL_ADDR = {htonl(0xAC100008)}; // 172.16.0.8
+ in_addr V4_GLOBAL_ADDR = {htonl(0x08080808)}; // 8.8.8.8
+
+ in6_addr V6_LOCAL_ADDR = {
+ {// 2001:db8:cafe::1
+ .u6_addr8 = {0x20, 0x01, 0x0d, 0xb8, 0xca, 0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}};
+ in6_addr V6_APP_LOCAL_ADDR = {
+ {// 2607:f0d0:1234::4
+ .u6_addr8 = {0x26, 0x07, 0xf0, 0xd0, 0x12, 0x34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}}};
+ in6_addr V6_GLOBAL_ADDR = {
+ {// 2607:1234:1002::4
+ .u6_addr8 = {0x26, 0x07, 0x12, 0x34, 0x10, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4}}};
+};
+
+const int SEND_TO_GLOBAL = 0;
+const int SEND_TO_SYSTEM_DEFAULT_LOCAL = 1;
+const int SEND_TO_PER_APP_DEFAULT_LOCAL = 2;
+
+// Exercise the combination of different explicitly selected network, different uid, local/non-local
+// address on local route exclusion VPN. E.g.
+// explicitlySelected systemDefault + uid in VPN range + no app default + non local address
+// explicitlySelected systemDefault + uid in VPN range + has app default + non local address
+// explicitlySelected systemDefault + uid in VPN range + has app default + local address
+// explicitlySelected appDefault + uid not in VPN range + has app default + non local address
+INSTANTIATE_TEST_SUITE_P(
+ PerAppDefaultNetwork, VpnLocalRoutesParameterizedTest,
+ testing::Combine(testing::Values(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, NETID_UNSET),
+ testing::Values(SEND_TO_GLOBAL, SEND_TO_SYSTEM_DEFAULT_LOCAL,
+ SEND_TO_PER_APP_DEFAULT_LOCAL),
+ testing::Bool(), testing::Bool(), testing::Bool(), testing::Bool()),
+ [](const testing::TestParamInfo<std::tuple<int, int, bool, bool, bool, bool>>& info) {
+ std::string explicitlySelected;
+ switch (std::get<0>(info.param)) {
+ case SYSTEM_DEFAULT_NETID:
+ explicitlySelected = "explicitlySelectedSystemDefault";
+ break;
+ case APP_DEFAULT_NETID:
+ explicitlySelected = "explicitlySelectedAppDefault";
+ break;
+ case NETID_UNSET:
+ explicitlySelected = "implicitlySelected";
+ break;
+ default:
+ explicitlySelected = "InvalidParameter"; // Should not happen.
+ }
+
+ std::string sendToAddr;
+ switch (std::get<1>(info.param)) {
+ case SEND_TO_GLOBAL:
+ sendToAddr = "GlobalAddr";
+ break;
+ case SEND_TO_SYSTEM_DEFAULT_LOCAL:
+ sendToAddr = "SystemLocal";
+ break;
+ case SEND_TO_PER_APP_DEFAULT_LOCAL:
+ sendToAddr = "AppLocal";
+ break;
+ default:
+ sendToAddr = "InvalidAddr"; // Should not happen.
+ }
+
+ const std::string isSubjectToVpn = std::get<2>(info.param)
+ ? std::string("SubjectToVpn")
+ : std::string("NotSubjectToVpn");
+
+ const std::string hasAppDefaultNetwork = std::get<3>(info.param)
+ ? std::string("HasAppDefault")
+ : std::string("NothasAppDefault");
+
+ const std::string testV6 =
+ std::get<4>(info.param) ? std::string("v6") : std::string("v4");
+
+ // Apply the same or different local address in app default and system default.
+ const std::string differentLocalRoutes = std::get<5>(info.param)
+ ? std::string("DifferentLocalRoutes")
+ : std::string("SameLocalAddr");
+
+ return explicitlySelected + "_uid" + isSubjectToVpn + hasAppDefaultNetwork +
+ "Range_with" + testV6 + sendToAddr + differentLocalRoutes;
+ });
+
+int getTargetIfaceForLocalRoutesExclusion(bool isSubjectToVpn, bool hasAppDefaultNetwork,
+ bool differentLocalRoutes, int sendToAddr,
+ int selectedNetId, int fallthroughFd, int appDefaultFd,
+ int vpnFd) {
+ int expectedIface;
+
+ // Setup the expected interface based on the condition.
+ if (isSubjectToVpn && hasAppDefaultNetwork) {
+ switch (sendToAddr) {
+ case SEND_TO_GLOBAL:
+ expectedIface = vpnFd;
+ break;
+ case SEND_TO_SYSTEM_DEFAULT_LOCAL:
+ // Go to app default if the app default and system default are the same range
+ // TODO(b/237351736): It should go to VPN if the system local and app local are
+ // different.
+ expectedIface = differentLocalRoutes ? fallthroughFd : appDefaultFd;
+ break;
+ case SEND_TO_PER_APP_DEFAULT_LOCAL:
+ expectedIface = appDefaultFd;
+ break;
+ default:
+ expectedIface = -1; // should not happen
+ }
+ } else if (isSubjectToVpn && !hasAppDefaultNetwork) {
+ switch (sendToAddr) {
+ case SEND_TO_GLOBAL:
+ expectedIface = vpnFd;
+ break;
+ case SEND_TO_SYSTEM_DEFAULT_LOCAL:
+ // TODO(b/237351736): It should go to app default if the system local and app local
+ // are different.
+ expectedIface = fallthroughFd;
+ break;
+ case SEND_TO_PER_APP_DEFAULT_LOCAL:
+ // Go to system default if the system default and app default are the same range.
+ expectedIface = differentLocalRoutes ? vpnFd : fallthroughFd;
+ break;
+ default:
+ expectedIface = -1; // should not happen
+ }
+ } else if (!isSubjectToVpn && hasAppDefaultNetwork) {
+ expectedIface = appDefaultFd;
+ } else { // !isSubjectToVpn && !hasAppDefaultNetwork
+ expectedIface = fallthroughFd;
+ }
+
+ // Override the target if it's explicitly selected.
+ switch (selectedNetId) {
+ case SYSTEM_DEFAULT_NETID:
+ expectedIface = fallthroughFd;
+ break;
+ case APP_DEFAULT_NETID:
+ expectedIface = appDefaultFd;
+ break;
+ default:
+ break;
+ // Based on the uid range.
+ }
+
+ return expectedIface;
+}
+
+// Routes configured on the system default network and on the VPN.
+// This allows the test to verify the worst case where the physical network and the VPN configure
+// the same routes. This ensures that routing is determined by the IP rules and doesn't just happen
+// to work because the routes don't overlap. If differentLocalRoutes is false, these routes are also
+// configured on the per-app default network.
+// For both IPv4 and IPv6, the first route is local, the second is not.
+std::vector<std::string> SYSTEM_DEFAULT_ROUTES = {"192.168.0.0/16", "0.0.0.0/0",
+ "2001:db8:cafe::/48", "::/0"};
+// Routes configured on the per-app default network if differentLocalRoutes is true.
+// For both IPv4 and IPv6, the first route is local, the second is not.
+std::vector<std::string> APP_DEFAULT_ROUTES = {"172.16.0.0/16", "0.0.0.0/0", "2607:f0d0:1234::/48",
+ "::/0"};
+void NetdBinderTest::setupNetworkRoutesForVpnAndDefaultNetworks(
+ int systemDefaultNetId, int appDefaultNetId, int vpnNetId, int otherNetId, bool secure,
+ bool testV6, bool differentLocalRoutes, std::vector<UidRangeParcel>&& appDefaultUidRanges,
+ std::vector<UidRangeParcel>&& vpnUidRanges) {
+ // Create a physical network on sTun, and set it as the system default network
+ createAndSetDefaultNetwork(systemDefaultNetId, sTun.name());
+
+ // Routes are configured to system default, app default and vpn network to verify if the packets
+ // are routed correctly.
+
+ // Setup system default routing.
+ for (const auto& route : SYSTEM_DEFAULT_ROUTES) {
+ EXPECT_TRUE(mNetd->networkAddRoute(systemDefaultNetId, sTun.name(), route, "").isOk());
+ }
+
+ // Create another physical network on sTun2 as per app default network
+ createPhysicalNetwork(appDefaultNetId, sTun2.name());
+
+ // Setup app default routing.
+ std::vector<std::string> appDefaultRoutes =
+ (differentLocalRoutes ? APP_DEFAULT_ROUTES : SYSTEM_DEFAULT_ROUTES);
+ for (const auto& route : appDefaultRoutes) {
+ EXPECT_TRUE(mNetd->networkAddRoute(appDefaultNetId, sTun2.name(), route, "").isOk());
+ }
+
+ // Create a bypassable VPN on sTun3.
+ auto config = makeNativeNetworkConfig(vpnNetId, NativeNetworkType::VIRTUAL,
+ INetd::PERMISSION_NONE, secure, true);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(vpnNetId, sTun3.name()).isOk());
+
+ // Setup vpn routing.
+ for (const auto& route : SYSTEM_DEFAULT_ROUTES) {
+ EXPECT_TRUE(mNetd->networkAddRoute(vpnNetId, sTun3.name(), route, "").isOk());
+ }
+
+ // Create another interface that is neither system default nor the app default to make sure
+ // the traffic won't be mis-routed.
+ createPhysicalNetwork(otherNetId, sTun4.name());
+ EXPECT_TRUE(mNetd->networkAddRoute(otherNetId, sTun4.name(), testV6 ? "::/0" : "0.0.0.0/0", "")
+ .isOk());
+ // Add per-app uid ranges.
+ EXPECT_TRUE(mNetd->networkAddUidRanges(appDefaultNetId, appDefaultUidRanges).isOk());
+
+ // Add VPN uid ranges.
+ EXPECT_TRUE(mNetd->networkAddUidRanges(vpnNetId, vpnUidRanges).isOk());
+}
+
+// Rules are in approximately the following order for bypassable VPNs that allow local network
+// access:
+// - Local routes to the per-app default network (UID guarded)
+// - Local routes to the system default network
+// - Both local and global routs to VPN network (UID guarded)
+// - Global routes to per-app default network(UID guarded)
+// - Global routes to system default network
+TEST_P(VpnLocalRoutesParameterizedTest, localRoutesExclusion) {
+ int selectedNetId;
+ int sendToAddr;
+ bool isSubjectToVpn;
+ bool hasAppDefaultNetwork;
+ bool testV6;
+ bool differentLocalRoutes;
+
+ std::tie(selectedNetId, sendToAddr, isSubjectToVpn, hasAppDefaultNetwork, testV6,
+ differentLocalRoutes) = GetParam();
+
+ setupNetworkRoutesForVpnAndDefaultNetworks(
+ SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID, TEST_NETID4, false /* secure */,
+ testV6, differentLocalRoutes,
+ // Setup uid ranges for app default and VPN. Configure TEST_UID2 into both app default
+ // and VPN to verify the behavior when the uid exists in both network.
+ {makeUidRangeParcel(TEST_UID2, TEST_UID1)}, {makeUidRangeParcel(TEST_UID3, TEST_UID2)});
+
+ int fallthroughFd = sTun.getFdForTesting();
+ int appDefaultFd = sTun2.getFdForTesting();
+ int vpnFd = sTun3.getFdForTesting();
+
+ // Explicitly select network
+ setNetworkForProcess(selectedNetId);
+
+ int targetUid;
+
+ // Setup the expected testing uid
+ if (isSubjectToVpn) {
+ if (hasAppDefaultNetwork) {
+ targetUid = TEST_UID2;
+ } else {
+ targetUid = TEST_UID3;
+ }
+ } else {
+ if (hasAppDefaultNetwork) {
+ targetUid = TEST_UID1;
+ } else {
+ targetUid = TEST_UID4; // Not in any of the UID ranges.
+ }
+ }
+
+ // Get expected interface for the traffic.
+ int expectedIface = getTargetIfaceForLocalRoutesExclusion(
+ isSubjectToVpn, hasAppDefaultNetwork, differentLocalRoutes, sendToAddr, selectedNetId,
+ fallthroughFd, appDefaultFd, vpnFd);
+
+ // Verify the packets are sent to the expected interface.
+ Fwmark fwmark;
+ if (testV6) {
+ in6_addr addr;
+ switch (sendToAddr) {
+ case SEND_TO_GLOBAL:
+ addr = V6_GLOBAL_ADDR;
+ break;
+ case SEND_TO_SYSTEM_DEFAULT_LOCAL:
+ addr = V6_LOCAL_ADDR;
+ break;
+ case SEND_TO_PER_APP_DEFAULT_LOCAL:
+ addr = differentLocalRoutes ? V6_APP_LOCAL_ADDR : V6_LOCAL_ADDR;
+ break;
+ default:
+ break;
+ // should not happen
+ }
+ EXPECT_TRUE(sendIPv6PacketFromUid(targetUid, addr, &fwmark, expectedIface));
+ } else {
+ in_addr addr;
+ switch (sendToAddr) {
+ case SEND_TO_GLOBAL:
+ addr = V4_GLOBAL_ADDR;
+ break;
+ case SEND_TO_SYSTEM_DEFAULT_LOCAL:
+ addr = V4_LOCAL_ADDR;
+ break;
+ case SEND_TO_PER_APP_DEFAULT_LOCAL:
+ addr = differentLocalRoutes ? V4_APP_LOCAL_ADDR : V4_LOCAL_ADDR;
+ break;
+ default:
+ break;
+ // should not happen
+ }
+
+ EXPECT_TRUE(sendIPv4PacketFromUid(targetUid, addr, &fwmark, expectedIface));
+ }
+}
+
TEST_F(NetdBinderTest, NetworkCreate) {
auto config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL,
INetd::PERMISSION_NONE, false, false);
@@ -4410,11 +4745,6 @@ TEST_F(NetdBinderTest, UidRangeSubPriority_ValidateInputs) {
uidRangeConfig.subPriority = SUB_PRIORITY_2;
EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig).isOk());
- // For a single network, identical UID ranges with the same priority is invalid.
- status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
- EXPECT_FALSE(status.isOk());
- EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
-
// Overlapping ranges is invalid.
uidRangeConfig.uidRanges = {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1),
makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)};
@@ -4792,8 +5122,39 @@ TEST_F(PerAppNetworkPermissionsTest, PermissionOnlyAffectsUid) {
}
}
-class MDnsBinderTest : public ::testing::Test {
+class MDnsBinderTest : public NetNativeTestBase {
public:
+ class TestMDnsListener : public android::net::mdns::aidl::BnMDnsEventListener {
+ public:
+ Status onServiceRegistrationStatus(const RegistrationInfo& /*status*/) override {
+ // no-op
+ return Status::ok();
+ }
+ Status onServiceDiscoveryStatus(const DiscoveryInfo& /*status*/) override {
+ // no-op
+ return Status::ok();
+ }
+ Status onServiceResolutionStatus(const ResolutionInfo& /*status*/) override {
+ // no-op
+ return Status::ok();
+ }
+ Status onGettingServiceAddressStatus(const GetAddressInfo& status) override {
+ if (status.id == mOperationId) {
+ std::lock_guard lock(mCvMutex);
+ mCv.notify_one();
+ }
+ return Status::ok();
+ }
+ std::condition_variable& getCv() { return mCv; }
+ std::mutex& getCvMutex() { return mCvMutex; }
+ void setOperationId(int operationId) { mOperationId = operationId; }
+
+ private:
+ std::mutex mCvMutex;
+ std::condition_variable mCv;
+ int mOperationId;
+ };
+
MDnsBinderTest() {
sp<IServiceManager> sm = android::defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("mdns"));
@@ -4802,31 +5163,46 @@ class MDnsBinderTest : public ::testing::Test {
}
}
- void SetUp() override { ASSERT_NE(nullptr, mMDns.get()); }
+ void SetUp() override {
+ ASSERT_NE(nullptr, mMDns.get());
+ // Start the daemon for mdns operations.
+ mDaemonStarted = mMDns->startDaemon().isOk();
+ }
- void TearDown() override {}
+ void TearDown() override {
+ if (mDaemonStarted) mMDns->stopDaemon();
+ }
+
+ std::cv_status getServiceAddress(int operationId, const sp<TestMDnsListener>& listener);
protected:
sp<IMDns> mMDns;
-};
-class TestMDnsListener : public android::net::mdns::aidl::BnMDnsEventListener {
- public:
- Status onServiceRegistrationStatus(const RegistrationInfo& /* status */) override {
- return Status::ok();
- }
- Status onServiceDiscoveryStatus(const DiscoveryInfo& /* status */) override {
- return Status::ok();
- }
- Status onServiceResolutionStatus(const ResolutionInfo& /* status */) override {
- return Status::ok();
- }
- Status onGettingServiceAddressStatus(const GetAddressInfo& /* status */) override {
- return Status::ok();
- }
+ private:
+ bool mDaemonStarted = false;
};
+std::cv_status MDnsBinderTest::getServiceAddress(int operationId,
+ const sp<TestMDnsListener>& listener) {
+ GetAddressInfo info;
+ info.id = operationId;
+ info.hostname = "Android.local";
+ info.interfaceIdx = 0;
+ binder::Status status = mMDns->getServiceAddress(info);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+ auto& cv = listener->getCv();
+ auto& cvMutex = listener->getCvMutex();
+ std::unique_lock lock(cvMutex);
+ // Wait for a long time to prevent test flaky.
+ return cv.wait_for(lock, std::chrono::milliseconds(2500));
+}
+
TEST_F(MDnsBinderTest, EventListenerTest) {
+ SKIP_WITH_HWASAN; // TODO(b/253513842): Re-enable.
+ // Start the Binder thread pool.
+ android::ProcessState::self()->startThreadPool();
+
// Register a null listener.
binder::Status status = mMDns->registerEventListener(nullptr);
EXPECT_FALSE(status.isOk());
@@ -4835,8 +5211,8 @@ TEST_F(MDnsBinderTest, EventListenerTest) {
status = mMDns->unregisterEventListener(nullptr);
EXPECT_FALSE(status.isOk());
- // Register the test listener.
- android::sp<TestMDnsListener> testListener = new TestMDnsListener();
+ // Register a test listener
+ auto testListener = android::sp<TestMDnsListener>::make();
status = mMDns->registerEventListener(testListener);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
@@ -4844,7 +5220,28 @@ TEST_F(MDnsBinderTest, EventListenerTest) {
status = mMDns->registerEventListener(testListener);
EXPECT_FALSE(status.isOk());
+ // Verify the listener can receive callback.
+ int id = arc4random_uniform(10000); // use random number
+ testListener->setOperationId(id);
+ EXPECT_EQ(std::cv_status::no_timeout, getServiceAddress(id, testListener));
+ // Stop getting address operation to release the service reference on MDnsSd
+ status = mMDns->stopOperation(id);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
// Unregister the test listener
status = mMDns->unregisterEventListener(testListener);
EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+ // Verify the listener can not receive callback.
+ testListener->setOperationId(id + 1);
+ EXPECT_EQ(std::cv_status::timeout, getServiceAddress(id + 1, testListener));
+ // Stop getting address operation to release the service reference on MDnsSd
+ status = mMDns->stopOperation(id + 1);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+ // Registering and unregistering the listener again should work.
+ status = mMDns->registerEventListener(testListener);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ status = mMDns->unregisterEventListener(testListener);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
}
diff --git a/tests/bpf_base_test.cpp b/tests/bpf_base_test.cpp
deleted file mode 100644
index 187ab8b3..00000000
--- a/tests/bpf_base_test.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include <string>
-
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <linux/inet_diag.h>
-#include <linux/sock_diag.h>
-#include <net/if.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-
-#include <cutils/qtaguid.h>
-#include <processgroup/processgroup.h>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "bpf/BpfMap.h"
-#include "bpf/BpfUtils.h"
-#include "bpf_shared.h"
-
-using android::base::Result;
-
-namespace android {
-namespace bpf {
-
-// Use the upper limit of uid to avoid conflict with real app uids. We can't use UID_MAX because
-// it's -1, which is INVALID_UID.
-constexpr uid_t TEST_UID = UID_MAX - 1;
-constexpr uint32_t TEST_TAG = 42;
-
-class BpfBasicTest : public testing::Test {
- protected:
- BpfBasicTest() {}
-};
-
-TEST_F(BpfBasicTest, TestCgroupMounted) {
- std::string cg2_path;
- ASSERT_EQ(true, CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, &cg2_path));
- ASSERT_EQ(0, access(cg2_path.c_str(), R_OK));
- ASSERT_EQ(0, access((cg2_path + "/cgroup.controllers").c_str(), R_OK));
-}
-
-TEST_F(BpfBasicTest, TestTrafficControllerSetUp) {
- ASSERT_EQ(0, access(BPF_EGRESS_PROG_PATH, R_OK));
- ASSERT_EQ(0, access(BPF_INGRESS_PROG_PATH, R_OK));
- ASSERT_EQ(0, access(XT_BPF_INGRESS_PROG_PATH, R_OK));
- ASSERT_EQ(0, access(XT_BPF_EGRESS_PROG_PATH, R_OK));
- ASSERT_EQ(0, access(COOKIE_TAG_MAP_PATH, R_OK));
- ASSERT_EQ(0, access(UID_COUNTERSET_MAP_PATH, R_OK));
- ASSERT_EQ(0, access(STATS_MAP_A_PATH, R_OK));
- ASSERT_EQ(0, access(STATS_MAP_B_PATH, R_OK));
- ASSERT_EQ(0, access(IFACE_INDEX_NAME_MAP_PATH, R_OK));
- ASSERT_EQ(0, access(IFACE_STATS_MAP_PATH, R_OK));
- ASSERT_EQ(0, access(CONFIGURATION_MAP_PATH, R_OK));
- ASSERT_EQ(0, access(UID_OWNER_MAP_PATH, R_OK));
-}
-
-TEST_F(BpfBasicTest, TestSocketFilterSetUp) {
- ASSERT_EQ(0, access(CGROUP_SOCKET_PROG_PATH, R_OK));
- ASSERT_EQ(0, access(UID_PERMISSION_MAP_PATH, R_OK));
-}
-
-TEST_F(BpfBasicTest, TestTagSocket) {
- BpfMap<uint64_t, UidTagValue> cookieTagMap(COOKIE_TAG_MAP_PATH);
- ASSERT_TRUE(cookieTagMap.isValid());
- int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
- ASSERT_LE(0, sock);
- uint64_t cookie = getSocketCookie(sock);
- ASSERT_NE(NONEXISTENT_COOKIE, cookie);
- ASSERT_EQ(0, qtaguid_tagSocket(sock, TEST_TAG, TEST_UID));
- Result<UidTagValue> tagResult = cookieTagMap.readValue(cookie);
- ASSERT_RESULT_OK(tagResult);
- ASSERT_EQ(TEST_UID, tagResult.value().uid);
- ASSERT_EQ(TEST_TAG, tagResult.value().tag);
- ASSERT_EQ(0, qtaguid_untagSocket(sock));
- tagResult = cookieTagMap.readValue(cookie);
- ASSERT_FALSE(tagResult.ok());
- ASSERT_EQ(ENOENT, tagResult.error().code());
-}
-
-TEST_F(BpfBasicTest, TestCloseSocketWithoutUntag) {
- BpfMap<uint64_t, UidTagValue> cookieTagMap(COOKIE_TAG_MAP_PATH);
- ASSERT_TRUE(cookieTagMap.isValid());
- int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
- ASSERT_LE(0, sock);
- uint64_t cookie = getSocketCookie(sock);
- ASSERT_NE(NONEXISTENT_COOKIE, cookie);
- ASSERT_EQ(0, qtaguid_tagSocket(sock, TEST_TAG, TEST_UID));
- Result<UidTagValue> tagResult = cookieTagMap.readValue(cookie);
- ASSERT_RESULT_OK(tagResult);
- ASSERT_EQ(TEST_UID, tagResult.value().uid);
- ASSERT_EQ(TEST_TAG, tagResult.value().tag);
- ASSERT_EQ(0, close(sock));
- // Check map periodically until sk destroy handler have done its job.
- for (int i = 0; i < 10; i++) {
- usleep(5000); // 5ms
- tagResult = cookieTagMap.readValue(cookie);
- if (!tagResult.ok()) {
- ASSERT_EQ(ENOENT, tagResult.error().code());
- return;
- }
- }
- FAIL() << "socket tag still exist after 50ms";
-}
-
-}
-}
diff --git a/tests/kernel_test.cpp b/tests/kernel_test.cpp
index 2cc5c99a..b9e1875e 100644
--- a/tests/kernel_test.cpp
+++ b/tests/kernel_test.cpp
@@ -58,6 +58,7 @@ bool isGsiImage() {
* CONFIG_NET_CLS_MATCHALL=y
* CONFIG_NET_ACT_POLICE=y
* CONFIG_NET_ACT_BPF=y
+ * CONFIG_BPF_JIT=y
*/
TEST(KernelTest, TestRateLimitingSupport) {
if (isGsiImage()) {
@@ -68,6 +69,7 @@ TEST(KernelTest, TestRateLimitingSupport) {
ASSERT_TRUE(configVerifier.hasOption("CONFIG_NET_CLS_MATCHALL"));
ASSERT_TRUE(configVerifier.hasOption("CONFIG_NET_ACT_POLICE"));
ASSERT_TRUE(configVerifier.hasOption("CONFIG_NET_ACT_BPF"));
+ ASSERT_TRUE(configVerifier.hasOption("CONFIG_BPF_JIT"));
}
} // namespace net
diff --git a/tests/netd_test.cpp b/tests/netd_test.cpp
index 8d5d8bc0..a04a6a76 100644
--- a/tests/netd_test.cpp
+++ b/tests/netd_test.cpp
@@ -29,6 +29,7 @@
#include <gtest/gtest.h>
+#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#define LOG_TAG "NetdTest"
@@ -70,6 +71,47 @@ TEST(NetdSELinuxTest, CheckProperMTULabels) {
"'^u:object_r:sysfs_net:s0 /sys/class/net/'"));
}
+static void assertBpfContext(const char* const target, const char* const label) {
+ // Use 'ls' cli utility to print the selinux context of the target directory or file.
+ // egrep -q will return 0 if it matches, ie. if the selinux context is as expected
+ std::string cmd = android::base::StringPrintf("ls -dZ %s | egrep -q '^u:object_r:%s:s0 %s$'",
+ target, label, target);
+
+ // NOLINTNEXTLINE(cert-env33-c)
+ ASSERT_EQ(W_EXITCODE(0, 0), system(cmd.c_str())) << cmd << " - did not return success(0)"
+ " - is kernel missing https://android-review.googlesource.com/c/kernel/common/+/1831252"
+ " 'UPSTREAM: security: selinux: allow per-file labeling for bpffs' ?";
+}
+
+// This test will fail if kernel is missing:
+// https://android-review.googlesource.com/c/kernel/common/+/1831252
+// UPSTREAM: security: selinux: allow per-file labeling for bpffs
+TEST(NetdSELinuxTest, CheckProperBpfLabels) {
+ assertBpfContext("/sys/fs/bpf", "fs_bpf");
+ assertBpfContext("/sys/fs/bpf/net_private", "fs_bpf_net_private");
+ assertBpfContext("/sys/fs/bpf/net_shared", "fs_bpf_net_shared");
+ assertBpfContext("/sys/fs/bpf/netd_readonly", "fs_bpf_netd_readonly");
+ assertBpfContext("/sys/fs/bpf/netd_shared", "fs_bpf_netd_shared");
+ assertBpfContext("/sys/fs/bpf/vendor", "fs_bpf_vendor");
+ assertBpfContext("/sys/fs/bpf/loader", "fs_bpf_loader");
+}
+
+bool isTetheringInProcess() {
+ int v = access("/apex/com.android.tethering/etc/flag/in-process", F_OK);
+ if (!v) return true;
+ EXPECT_EQ(v, -1) << "expected return of found(0) or notfound(-1/ENOENT)";
+ EXPECT_EQ(errno, ENOENT) << "expected return of found(0) or notfound(-1/ENOENT)";
+ return false;
+}
+
+TEST(NetdSELinuxTest, CheckProperBpfTetheringLabels) {
+ if (isTetheringInProcess()) {
+ assertBpfContext("/sys/fs/bpf/net_shared/tethering", "fs_bpf_net_shared");
+ } else {
+ assertBpfContext("/sys/fs/bpf/tethering", "fs_bpf_tethering");
+ }
+}
+
// Trivial thread function that simply immediately terminates successfully.
static int thread(void*) {
return 0;
diff --git a/tests/sock_diag_test.cpp b/tests/sock_diag_test.cpp
index 8ee99083..5d142dc4 100644
--- a/tests/sock_diag_test.cpp
+++ b/tests/sock_diag_test.cpp
@@ -21,6 +21,7 @@
#include <linux/inet_diag.h>
#include <gtest/gtest.h>
+#include <netdutils/NetNativeTestBase.h>
#include "NetdConstants.h"
#include "SockDiag.h"
@@ -29,7 +30,7 @@
#define NUM_SOCKETS 500
-class SockDiagTest : public ::testing::Test {
+class SockDiagTest : public NetNativeTestBase {
};
uint16_t bindAndListen(int s) {
diff --git a/tests/test_utils.h b/tests/test_utils.h
index de6c221f..25642558 100644
--- a/tests/test_utils.h
+++ b/tests/test_utils.h
@@ -21,6 +21,9 @@
#include <string>
#include <vector>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
int randomUid();
std::vector<std::string> runCommand(const std::string& command);
@@ -37,3 +40,21 @@ std::vector<std::string> listIpRoutes(const char* ipVersion, const char* table);
bool ipRouteExists(const char* ipVersion, const char* table,
const std::vector<std::string>& ipRouteSubstrings);
+
+// Require root (for seteuid).
+class ScopedUidChange {
+ public:
+ explicit ScopedUidChange(uid_t uid) : mInputUid(uid) {
+ mStoredUid = geteuid();
+ if (mInputUid == mStoredUid) return;
+ EXPECT_TRUE(seteuid(uid) == 0);
+ }
+ ~ScopedUidChange() {
+ if (mInputUid == mStoredUid) return;
+ EXPECT_TRUE(seteuid(mStoredUid) == 0);
+ }
+
+ private:
+ uid_t mInputUid;
+ uid_t mStoredUid;
+};