summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Chen <cken@google.com>2021-03-17 01:57:19 +0800
committerKen Chen <cken@google.com>2021-03-26 10:32:49 +0800
commit4e8ef9b24e5f5c1f9760f593e2e022750c314f5e (patch)
tree27b326d21ae707a076d24c7b3277d39dae9928c7
parentb573648fce613ecd94dce54a8744e6e06544856c (diff)
downloadnetd-4e8ef9b24e5f5c1f9760f593e2e022750c314f5e.tar.gz
PANS - Support unreachable default network
Framework provides several preferences in PANS feature. To meet those preferences, Netd needs to support two operations for framework: (1) Set OEM-paid network as default network for apps. (2) Prohibit apps to use default network if it is not explicitly selected. The #1 is supported by previous commit already. This commit implements the #2, which adds a new IP rule priority for unconnected socket, reuses existing IP rule priorities in explicit and implicit network selection. Rules are looks like: 15000: from all fwmark 0x10034/0x1ffff iif lo uidrange x-y unreachable ... 22000: from all fwmark 0x34/0x1ffff iif lo uidrange x-y unreachable ... 27000: from all fwmark 0x0/0xffff iif lo uidrange x-y unreachable An UNREACHABLE network (netId 52) is created for framework to specify that the default network is unavailable for designated apps. Bug: 181579204 Test: atest Change-Id: I21530928a85870df673e2d1387fde130fe5a0104
-rw-r--r--server/Android.bp1
-rw-r--r--server/DummyNetwork.cpp3
-rw-r--r--server/Network.cpp3
-rw-r--r--server/Network.h3
-rw-r--r--server/NetworkController.cpp37
-rw-r--r--server/NetworkController.h6
-rw-r--r--server/RouteController.cpp73
-rw-r--r--server/RouteController.h59
-rw-r--r--server/UnreachableNetwork.cpp58
-rw-r--r--server/UnreachableNetwork.h33
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl24
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl15
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl15
-rw-r--r--server/binder/android/net/INetd.aidl8
-rw-r--r--tests/binder_test.cpp130
21 files changed, 510 insertions, 48 deletions
diff --git a/server/Android.bp b/server/Android.bp
index 5cb4d77c..4b5f6137 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -273,6 +273,7 @@ cc_binary {
"PhysicalNetwork.cpp",
"PppController.cpp",
"Process.cpp",
+ "UnreachableNetwork.cpp",
"VirtualNetwork.cpp",
"main.cpp",
"oem_iptables_hook.cpp",
diff --git a/server/DummyNetwork.cpp b/server/DummyNetwork.cpp
index 8ce2826f..e6103a15 100644
--- a/server/DummyNetwork.cpp
+++ b/server/DummyNetwork.cpp
@@ -18,9 +18,6 @@
#include "DummyNetwork.h"
-#include "RouteController.h"
-
-#include "log/log.h"
#include "errno.h"
namespace android {
diff --git a/server/Network.cpp b/server/Network.cpp
index ca53ccaa..8179d8b5 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -74,6 +74,9 @@ std::string Network::toString() const {
case PHYSICAL:
repr << "PHYSICAL";
break;
+ case UNREACHABLE:
+ repr << "UNREACHABLE";
+ break;
case VIRTUAL:
repr << "VIRTUAL";
break;
diff --git a/server/Network.h b/server/Network.h
index e7384f9e..b12c67b7 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -31,6 +31,7 @@ public:
DUMMY,
LOCAL,
PHYSICAL,
+ UNREACHABLE,
VIRTUAL,
};
@@ -56,7 +57,9 @@ public:
[[nodiscard]] virtual int removeUsers(const UidRanges&) { return -EINVAL; };
bool isSecure() const;
bool isPhysical() { return getType() == PHYSICAL; }
+ bool isUnreachable() { return getType() == UNREACHABLE; }
bool isVirtual() { return getType() == VIRTUAL; }
+ bool canAddUsers() { return isPhysical() || isVirtual() || isUnreachable(); }
protected:
explicit Network(unsigned netId, bool mSecure = false);
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 9e13d454..65658a52 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -39,6 +39,7 @@
#include "OffloadUtils.h"
#include "PhysicalNetwork.h"
#include "RouteController.h"
+#include "UnreachableNetwork.h"
#include "VirtualNetwork.h"
#include "netdutils/DumpWriter.h"
#include "netid_client.h"
@@ -142,6 +143,7 @@ NetworkController::NetworkController() :
mProtectableUsers({AID_VPN}) {
mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
mNetworks[DUMMY_NET_ID] = new DummyNetwork(DUMMY_NET_ID);
+ mNetworks[UNREACHABLE_NET_ID] = new UnreachableNetwork(UNREACHABLE_NET_ID);
// Clear all clsact stubs on all interfaces.
// TODO: perhaps only remove the clsact on the interface which is added by
@@ -205,7 +207,7 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
fwmark.protectedFromVpn = true;
fwmark.permission = PERMISSION_SYSTEM;
- PhysicalNetwork* appDefaultNetwork = getPhysicalNetworkForUserLocked(uid);
+ Network* appDefaultNetwork = getPhysicalOrUnreachableNetworkForUserLocked(uid);
unsigned defaultNetId = appDefaultNetwork ? appDefaultNetwork->getNetId() : mDefaultNetId;
// Common case: there is no VPN that applies to the user, and the query did not specify a netId.
@@ -252,15 +254,15 @@ uint32_t NetworkController::getNetworkForDnsLocked(unsigned* netId, uid_t uid) c
}
// Returns the NetId that a given UID would use if no network is explicitly selected. Specifically,
-// the VPN that applies to the UID if any; otherwise, the default network for UID; lastly, the
-// default network.
+// the VPN that applies to the UID if any; Otherwise, the unreachable network that applies to the
+// UID; Otherwise, the default network for UID; lastly, the default network.
unsigned NetworkController::getNetworkForUser(uid_t uid) const {
ScopedRLock lock(mRWLock);
if (VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid)) {
return virtualNetwork->getNetId();
}
- if (PhysicalNetwork* physicalNetwork = getPhysicalNetworkForUserLocked(uid)) {
- return physicalNetwork->getNetId();
+ if (Network* network = getPhysicalOrUnreachableNetworkForUserLocked(uid)) {
+ return network->getNetId();
}
return mDefaultNetId;
}
@@ -292,8 +294,8 @@ unsigned NetworkController::getNetworkForConnectLocked(uid_t uid) const {
if (virtualNetwork && !virtualNetwork->isSecure()) {
return virtualNetwork->getNetId();
}
- if (PhysicalNetwork* physicalNetwork = getPhysicalNetworkForUserLocked(uid)) {
- return physicalNetwork->getNetId();
+ if (Network* network = getPhysicalOrUnreachableNetworkForUserLocked(uid)) {
+ return network->getNetId();
}
return mDefaultNetId;
}
@@ -456,8 +458,8 @@ int NetworkController::createVirtualNetwork(unsigned netId, bool secure) {
int NetworkController::destroyNetwork(unsigned netId) {
ScopedWLock lock(mRWLock);
- if (netId == LOCAL_NET_ID) {
- ALOGE("cannot destroy local network");
+ if (netId == LOCAL_NET_ID || netId == UNREACHABLE_NET_ID) {
+ ALOGE("cannot destroy local or unreachable network");
return -EINVAL;
}
if (!isValidNetworkLocked(netId)) {
@@ -597,7 +599,7 @@ int isWrongNetworkForUidRanges(unsigned netId, Network* network) {
ALOGE("no such netId %u", netId);
return -ENONET;
}
- if (!network->isVirtual() && !network->isPhysical()) {
+ if (!network->canAddUsers()) {
ALOGE("cannot add/remove users to/from network %u, type %d", netId, network->getType());
return -EINVAL;
}
@@ -774,13 +776,19 @@ VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) con
return nullptr;
}
-PhysicalNetwork* NetworkController::getPhysicalNetworkForUserLocked(uid_t uid) const {
+Network* NetworkController::getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const {
+ // Unreachable network take precedence over OEM-paid network.
+ auto iter = mNetworks.find(UNREACHABLE_NET_ID);
+ if (iter != mNetworks.end() && iter->second->appliesToUser(uid)) {
+ return iter->second;
+ }
+
for (const auto& [_, network] : mNetworks) {
if (network->isPhysical() && network->appliesToUser(uid)) {
// Return the first physical network that matches UID.
// If there is more than one such network, the behaviour is undefined.
// This is a configuration error.
- return static_cast<PhysicalNetwork*>(network);
+ return network;
}
}
return nullptr;
@@ -821,6 +829,11 @@ int NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) c
mProtectableUsers.find(uid) == mProtectableUsers.end()) {
return -EPERM;
}
+ // Anyone can use unreachable network if they want. That being said, PANS should be the only
+ // user so far.
+ if (network->isUnreachable()) {
+ return 0;
+ }
// If the UID wants to use a physical network and it has a UID range that includes the UID, the
// UID has permission to use it regardless of whether the permission bits match.
if (network->isPhysical() && network->appliesToUser(uid)) {
diff --git a/server/NetworkController.h b/server/NetworkController.h
index a7871556..271f3e58 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -23,6 +23,7 @@
#include "NetdConstants.h"
#include "Permission.h"
#include "PhysicalNetwork.h"
+#include "UnreachableNetwork.h"
#include "android/net/INetd.h"
#include "netdutils/DumpWriter.h"
@@ -83,11 +84,12 @@ class VirtualNetwork;
*/
class NetworkController {
public:
- // NetIds 52..98 are reserved for future use.
+ // NetIds 53..98 are reserved for future use.
static constexpr int MIN_OEM_ID = 1;
static constexpr int MAX_OEM_ID = 50;
static constexpr int LOCAL_NET_ID = INetd::LOCAL_NET_ID;
static constexpr int DUMMY_NET_ID = INetd::DUMMY_NET_ID;
+ static constexpr int UNREACHABLE_NET_ID = INetd::UNREACHABLE_NET_ID;
// Route mode for modify route
enum RouteOperation { ROUTE_ADD, ROUTE_UPDATE, ROUTE_REMOVE };
@@ -159,7 +161,7 @@ public:
bool canProtectLocked(uid_t uid) const;
bool isVirtualNetworkLocked(unsigned netId) const;
VirtualNetwork* getVirtualNetworkForUserLocked(uid_t uid) const;
- PhysicalNetwork* getPhysicalNetworkForUserLocked(uid_t uid) const;
+ 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);
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index dad824f9..666a88a7 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -850,6 +850,71 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
return 0;
}
+[[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd,
+ bool add, bool explicitSelect) {
+ if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
+ ALOGE("modifyUidUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
+ return -EUSERS;
+ }
+
+ Fwmark fwmark;
+ Fwmark mask;
+
+ fwmark.netId = netId;
+ mask.netId = FWMARK_NET_ID_MASK;
+
+ fwmark.explicitlySelected = explicitSelect;
+ mask.explicitlySelected = true;
+
+ // Access to this network is controlled by UID rules, not permission bits.
+ fwmark.permission = PERMISSION_NONE;
+ mask.permission = PERMISSION_NONE;
+
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ explicitSelect ? RULE_PRIORITY_UID_EXPLICIT_NETWORK
+ : RULE_PRIORITY_UID_IMPLICIT_NETWORK,
+ FR_ACT_UNREACHABLE, RT_TABLE_UNSPEC, fwmark.intValue, mask.intValue,
+ IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+}
+
+[[nodiscard]] static int modifyUidDefaultUnreachableRule(uid_t uidStart, uid_t uidEnd, bool add) {
+ if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
+ ALOGE("modifyUidDefaultNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
+ return -EUSERS;
+ }
+
+ Fwmark fwmark;
+ Fwmark mask;
+
+ fwmark.netId = NETID_UNSET;
+ mask.netId = FWMARK_NET_ID_MASK;
+
+ // Access to this network is controlled by UID rules, not permission bits.
+ fwmark.permission = PERMISSION_NONE;
+ mask.permission = PERMISSION_NONE;
+
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_UID_DEFAULT_UNREACHABLE,
+ FR_ACT_UNREACHABLE, RT_TABLE_UNSPEC, fwmark.intValue, mask.intValue,
+ IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+}
+
+int RouteController::modifyUnreachableNetwork(unsigned netId, const UidRanges& uidRanges,
+ bool add) {
+ for (const UidRangeParcel& range : uidRanges.getRanges()) {
+ if (int ret = modifyUidUnreachableRule(netId, range.start, range.stop, add, EXPLICIT)) {
+ return ret;
+ }
+ if (int ret = modifyUidUnreachableRule(netId, range.start, range.stop, add, IMPLICIT)) {
+ return ret;
+ }
+ if (int ret = modifyUidDefaultUnreachableRule(range.start, range.stop, add)) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
[[nodiscard]] static int modifyRejectNonSecureNetworkRule(const UidRanges& uidRanges, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -1243,6 +1308,14 @@ int RouteController::removeUsersFromPhysicalNetwork(unsigned netId, const char*
!MODIFY_NON_UID_BASED_RULES);
}
+int RouteController::addUsersToUnreachableNetwork(unsigned netId, const UidRanges& uidRanges) {
+ return modifyUnreachableNetwork(netId, uidRanges, ACTION_ADD);
+}
+
+int RouteController::removeUsersFromUnreachableNetwork(unsigned netId, const UidRanges& uidRanges) {
+ return modifyUnreachableNetwork(netId, uidRanges, ACTION_DEL);
+}
+
// Protects sInterfaceToTable.
std::mutex RouteController::sInterfaceToTableLock;
std::map<std::string, uint32_t> RouteController::sInterfaceToTable;
diff --git a/server/RouteController.h b/server/RouteController.h
index 8495462c..a6a8bb03 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -29,11 +29,11 @@
namespace android::net {
// clang-format off
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
-const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF = 11000;
-const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 12000;
-const uint32_t RULE_PRIORITY_SECURE_VPN = 13000;
-const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN = 14000;
+const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
+const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF = 11000;
+const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 12000;
+const uint32_t RULE_PRIORITY_SECURE_VPN = 13000;
+const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN = 14000;
// Rules used when applications explicitly select a network that they have permission to use only
// because they are in the list of UID ranges for that network.
//
@@ -41,23 +41,35 @@ const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN = 14000;
// not have the necessary permission bits in the fwmark. We cannot just give any socket on any of
// these networks the permission bits, because if the UID that created the socket loses access to
// the network, then the socket must not match any rule that selects that network.
-const uint32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK = 15000;
-const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK = 16000;
-const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE = 17000;
-const uint32_t RULE_PRIORITY_LEGACY_SYSTEM = 18000;
-const uint32_t RULE_PRIORITY_LEGACY_NETWORK = 19000;
-const uint32_t RULE_PRIORITY_LOCAL_NETWORK = 20000;
-const uint32_t RULE_PRIORITY_TETHERING = 21000;
+const uint32_t RULE_PRIORITY_UID_EXPLICIT_NETWORK = 15000;
+const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK = 16000;
+const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE = 17000;
+const uint32_t RULE_PRIORITY_LEGACY_SYSTEM = 18000;
+const uint32_t RULE_PRIORITY_LEGACY_NETWORK = 19000;
+const uint32_t RULE_PRIORITY_LOCAL_NETWORK = 20000;
+const uint32_t RULE_PRIORITY_TETHERING = 21000;
// Implicit rules for sockets that connected on a given network because the network was the default
// network for the UID.
-const uint32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK = 22000;
-const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK = 23000;
-const uint32_t RULE_PRIORITY_BYPASSABLE_VPN = 24000;
-// reserved for RULE_PRIORITY_UID_VPN_FALLTHROUGH = 25000;
-const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 26000;
-const uint32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 27000;
-const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 28000;
-const uint32_t RULE_PRIORITY_UNREACHABLE = 32000;
+const uint32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK = 22000;
+const uint32_t RULE_PRIORITY_IMPLICIT_NETWORK = 23000;
+const uint32_t RULE_PRIORITY_BYPASSABLE_VPN = 24000;
+// reserved for RULE_PRIORITY_UID_VPN_FALLTHROUGH = 25000;
+const uint32_t RULE_PRIORITY_VPN_FALLTHROUGH = 26000;
+// Rule used when framework wants to disable default network from specified applications. There will
+// be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and
+// UID_DEFAULT_NETWORK when framework is switching user preferences.
+//
+// framework --> netd
+// step 1: set uid to unreachable network
+// step 2: remove uid from OEM-paid network list
+//
+// We have this priority so that the default network for apps will be blocked right after step 1.
+// The rule also provides flexibility, just in case we need to support the same uid constantly
+// exists in both UID_DEFAULT_UNREACHABLE and UID_DEFAULT_NETWORK in the future.
+const uint32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 27000;
+const uint32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 28000;
+const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 29000;
+const uint32_t RULE_PRIORITY_UNREACHABLE = 32000;
// clang-format on
class UidRanges;
@@ -148,6 +160,12 @@ public:
[[nodiscard]] static int removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
const UidRanges& uidRanges);
+ [[nodiscard]] static int addUsersToUnreachableNetwork(unsigned netId,
+ const UidRanges& uidRanges);
+
+ [[nodiscard]] static int removeUsersFromUnreachableNetwork(unsigned netId,
+ const UidRanges& uidRanges);
+
// For testing.
static int (*iptablesRestoreCommandFunction)(IptablesTarget, const std::string&,
const std::string&, std::string *);
@@ -168,6 +186,7 @@ private:
static int modifyPhysicalNetwork(unsigned netId, const char* interface,
const UidRanges& uidRanges, Permission permission, bool add,
bool modifyNonUidBasedRules);
+ static int modifyUnreachableNetwork(unsigned netId, const UidRanges& uidRanges, bool add);
static int modifyRoute(uint16_t action, uint16_t flags, const char* interface,
const char* destination, const char* nexthop, TableType tableType,
int mtu);
diff --git a/server/UnreachableNetwork.cpp b/server/UnreachableNetwork.cpp
new file mode 100644
index 00000000..0fb556b9
--- /dev/null
+++ b/server/UnreachableNetwork.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define LOG_TAG "Netd"
+
+#include "UnreachableNetwork.h"
+
+#include "RouteController.h"
+
+namespace android {
+namespace net {
+
+// The unreachable network is used to reject traffic. It is used for system purposes only.
+UnreachableNetwork::UnreachableNetwork(unsigned netId) : Network(netId) {}
+
+int UnreachableNetwork::addUsers(const UidRanges& uidRanges) {
+ if (hasInvalidUidRanges(uidRanges)) {
+ return -EINVAL;
+ }
+
+ int ret = RouteController::addUsersToUnreachableNetwork(mNetId, uidRanges);
+ if (ret) {
+ ALOGE("failed to add users to unreachable network");
+ return ret;
+ }
+ mUidRanges.add(uidRanges);
+ return 0;
+}
+
+int UnreachableNetwork::removeUsers(const UidRanges& uidRanges) {
+ int ret = RouteController::removeUsersFromUnreachableNetwork(mNetId, uidRanges);
+ if (ret) {
+ ALOGE("failed to remove users from unreachable network");
+ return ret;
+ }
+ mUidRanges.remove(uidRanges);
+ return 0;
+}
+
+Network::Type UnreachableNetwork::getType() const {
+ return UNREACHABLE;
+}
+
+} // namespace net
+} // namespace android
diff --git a/server/UnreachableNetwork.h b/server/UnreachableNetwork.h
new file mode 100644
index 00000000..c0da5466
--- /dev/null
+++ b/server/UnreachableNetwork.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 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 "Network.h"
+
+namespace android::net {
+
+class UnreachableNetwork : public Network {
+ public:
+ explicit UnreachableNetwork(unsigned netId);
+ [[nodiscard]] int addUsers(const UidRanges& uidRanges) override;
+ [[nodiscard]] int removeUsers(const UidRanges& uidRanges) override;
+
+ private:
+ Type getType() const override;
+};
+
+} // namespace android::net \ No newline at end of file
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
index a0d85a31..99a36e6e 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2016, 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
@@ -138,6 +153,7 @@ interface INetd {
const int PENALTY_POLICY_REJECT = 3;
const int LOCAL_NET_ID = 99;
const int DUMMY_NET_ID = 51;
+ const int UNREACHABLE_NET_ID = 52;
const String NEXTHOP_NONE = "";
const String NEXTHOP_UNREACHABLE = "unreachable";
const String NEXTHOP_THROW = "throw";
@@ -148,10 +164,14 @@ interface INetd {
const int PERMISSION_INTERNET = 4;
const int PERMISSION_UPDATE_DEVICE_STATS = 8;
const int PERMISSION_UNINSTALLED = -1;
- /* @deprecated use FIREWALL_ALLOWLIST. */
+ /**
+ * @deprecated use FIREWALL_ALLOWLIST.
+ */
const int FIREWALL_WHITELIST = 0;
const int FIREWALL_ALLOWLIST = 0;
- /* @deprecated use FIREWALL_DENYLIST. */
+ /**
+ * @deprecated use FIREWALL_DENYLIST.
+ */
const int FIREWALL_BLACKLIST = 1;
const int FIREWALL_DENYLIST = 1;
const int FIREWALL_RULE_ALLOW = 1;
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
index d86f4984..31775dfd 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetdUnsolicitedEventListener.aidl
@@ -1,3 +1,18 @@
+/**
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
index 95607576..1869d8d4 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/InterfaceConfigurationParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
index 74930914..8ea20d11 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/MarkMaskParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
index 691a77e6..5ef95e67 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/RouteInfoParcel.aidl
@@ -1,3 +1,18 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
index b568f4ad..7b39c22e 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherConfigParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
index a8e0a116..983e9860 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherOffloadRuleParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
index 9c268dff..5f1b7226 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
index 6ab3eee7..72e987a2 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/UidRangeParcel.aidl
@@ -1,3 +1,18 @@
+/*
+ * 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.
+ */
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index b84d6913..ee263933 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -779,6 +779,14 @@ interface INetd {
*/
const int DUMMY_NET_ID = 51;
+ /**
+ * Constant net ID for the "unreachable" network.
+ *
+ * The unreachable network is used to reject traffic. Any attempt to use it will fail
+ * with ENETUNREACH.
+ */
+ const int UNREACHABLE_NET_ID = 52;
+
// Route does not specify a next hop
const String NEXTHOP_NONE = "";
// Route next hop is unreachable
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index e8be7fa6..cfff6407 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -112,6 +112,7 @@ using android::net::RULE_PRIORITY_PROHIBIT_NON_VPN;
using android::net::RULE_PRIORITY_SECURE_VPN;
using android::net::RULE_PRIORITY_TETHERING;
using android::net::RULE_PRIORITY_UID_DEFAULT_NETWORK;
+using android::net::RULE_PRIORITY_UID_DEFAULT_UNREACHABLE;
using android::net::RULE_PRIORITY_UID_EXPLICIT_NETWORK;
using android::net::RULE_PRIORITY_UID_IMPLICIT_NETWORK;
using android::net::RULE_PRIORITY_VPN_FALLTHROUGH;
@@ -269,6 +270,7 @@ void testNetworkExistsButCannotConnect(const sp<INetd>& netd, const int netId) {
TEST_F(NetdBinderTest, InitialNetworksExist) {
testNetworkExistsButCannotConnect(mNetd, INetd::DUMMY_NET_ID);
testNetworkExistsButCannotConnect(mNetd, INetd::LOCAL_NET_ID);
+ testNetworkExistsButCannotConnect(mNetd, INetd::UNREACHABLE_NET_ID);
}
TEST_F(NetdBinderTest, IpSecTunnelInterface) {
@@ -3187,6 +3189,37 @@ bool sendIPv6PacketFromUid(uid_t uid, const in6_addr& dstAddr, Fwmark* fwmark, i
return true;
}
+// 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) {
+ ScopedUidChange scopedUidChange(uid);
+ unique_fd s(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
+ if (s < 0) return false;
+
+ const sockaddr_in6 dst6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = 42,
+ .sin6_addr = dstAddr,
+ };
+ if (doConnect) {
+ if (connect(s, (sockaddr*)&dst6, sizeof(dst6)) == 0) return false;
+ if (errno != expectedErr) return false;
+ }
+
+ socklen_t fwmarkLen = sizeof(fwmark->intValue);
+ EXPECT_NE(-1, getsockopt(s, SOL_SOCKET, SO_MARK, &(fwmark->intValue), &fwmarkLen));
+
+ char addr[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &dstAddr, addr, INET6_ADDRSTRLEN);
+ SCOPED_TRACE(StringPrintf("sendIPv6PacketFail, addr: %s, uid: %u, doConnect: %s", addr, uid,
+ doConnect ? "true" : "false"));
+ if (!doConnect) {
+ if (sendto(s, "foo", sizeof("foo"), 0, (sockaddr*)&dst6, sizeof(dst6)) == 0) return false;
+ if (errno != expectedErr) return false;
+ }
+ return true;
+}
+
void expectVpnFallthroughRuleExists(const std::string& ifName, int vpnNetId) {
std::string vpnFallthroughRule =
StringPrintf("%d:\tfrom all fwmark 0x%x/0xffff lookup %s",
@@ -3761,15 +3794,27 @@ namespace {
void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRangeParcel>& uidRanges,
const std::string& iface) {
ASSERT_EQ(expectedResults.size(), uidRanges.size());
- std::string action = StringPrintf("lookup %s ", iface.c_str());
-
- for (unsigned long i = 0; i < uidRanges.size(); i++) {
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK, uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK, uidRanges[i], action));
- EXPECT_EQ(expectedResults[i],
- ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_NETWORK, uidRanges[i], action));
+ if (iface.size()) {
+ std::string action = StringPrintf("lookup %s ", iface.c_str());
+ for (unsigned long i = 0; i < uidRanges.size(); i++) {
+ EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_NETWORK,
+ uidRanges[i], action));
+ }
+ } else {
+ std::string action = "unreachable";
+ for (unsigned long i = 0; i < uidRanges.size(); i++) {
+ EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_UNREACHABLE, uidRanges[i],
+ action));
+ }
}
}
@@ -3806,6 +3851,28 @@ void expectPacketSentOnNetId(uid_t uid, unsigned netId, int fd, int selectionMod
EXPECT_EQ(expected.intValue, fwmark.intValue);
}
+void expectUnreachableError(uid_t uid, unsigned netId, int selectionMode) {
+ Fwmark fwmark;
+ const bool doConnect = (selectionMode != UNCONNECTED_SOCKET);
+ EXPECT_TRUE(sendIPv6PacketFromUidFail(uid, V6_ADDR, &fwmark, doConnect, ENETUNREACH));
+
+ Fwmark expected;
+ expected.netId = netId;
+ expected.explicitlySelected = (selectionMode == EXPLICITLY_SELECT);
+ if (uid == AID_ROOT && selectionMode == EXPLICITLY_SELECT) {
+ expected.protectedFromVpn = true;
+ } else {
+ expected.protectedFromVpn = false;
+ }
+ if (selectionMode == UNCONNECTED_SOCKET) {
+ expected.permission = PERMISSION_NONE;
+ } else {
+ expected.permission = (uid == AID_ROOT) ? PERMISSION_SYSTEM : PERMISSION_NONE;
+ }
+
+ EXPECT_EQ(expected.intValue, fwmark.intValue);
+}
+
} // namespace
// Verify whether API reject overlapped UID ranges
@@ -3865,6 +3932,13 @@ TEST_F(NetdBinderTest, PerAppDefaultNetwork_VerifyIpRules) {
verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, sTun.name());
EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(1)}).isOk());
verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, sTun.name());
+
+ EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID, uidRanges).isOk());
+ verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, "");
+ EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(0)}).isOk());
+ verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, "");
+ EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(1)}).isOk());
+ verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, "");
}
// Verify whether packets go through the right network with and without per-app default network.
@@ -3896,6 +3970,18 @@ TEST_F(NetdBinderTest, PerAppDefaultNetwork_ImplicitlySelectNetwork) {
.isOk());
expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
+
+ // Prohibit TEST_UID1 from using the default network.
+ EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
+ .isOk());
+ expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
+ expectUnreachableError(TEST_UID1, INetd::UNREACHABLE_NET_ID, IMPLICITLY_SELECT);
+
+ // restore IP rules
+ EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
+ .isOk());
}
// Verify whether packets go through the right network when app explicitly selects a network.
@@ -3911,6 +3997,19 @@ TEST_F(NetdBinderTest, PerAppDefaultNetwork_ExplicitlySelectNetwork) {
expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
+ // Set TEST_UID1 to default unreachable, which won't affect the explicitly selected network.
+ // Connections go through the system default network.
+ EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
+ .isOk());
+ expectPacketSentOnNetId(AID_ROOT, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
+ expectPacketSentOnNetId(TEST_UID1, SYSTEM_DEFAULT_NETID, systemDefaultFd, EXPLICITLY_SELECT);
+
+ // restore IP rules
+ EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
+ .isOk());
+
// Add TEST_UID1 to per-app default network, which won't affect the explicitly selected network.
EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID,
{makeUidRangeParcel(TEST_UID1, TEST_UID1)})
@@ -3944,6 +4043,19 @@ TEST_F(NetdBinderTest, PerAppDefaultNetwork_UnconnectedSocket) {
.isOk());
expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
expectPacketSentOnNetId(TEST_UID1, NETID_UNSET, appDefaultFd, UNCONNECTED_SOCKET);
+
+ // Set TEST_UID1's default network to unreachable. Its traffic should get ENETUNREACH error.
+ // Other traffic still go through the system default network.
+ EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
+ .isOk());
+ expectPacketSentOnNetId(AID_ROOT, NETID_UNSET, systemDefaultFd, UNCONNECTED_SOCKET);
+ expectUnreachableError(TEST_UID1, NETID_UNSET, UNCONNECTED_SOCKET);
+
+ // restore IP rules
+ EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1)})
+ .isOk());
}
TEST_F(NetdBinderTest, PerAppDefaultNetwork_PermissionCheck) {