summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Chen <cken@google.com>2021-05-23 14:56:43 +0800
committerKen Chen <cken@google.com>2021-07-01 19:03:38 +0800
commitd9aa98aaad690d89cc9784fa7b578bcd7b0446eb (patch)
tree3b439f18efe352c24e8112b07e037298fe6bc793
parent2d4975f0c055ed9ee6ef9050c03fb19214d648b5 (diff)
downloadnetd-d9aa98aaad690d89cc9784fa7b578bcd7b0446eb.tar.gz
Support subsidiary priority on UID ranges
Network preference per-profile and OEM network preferences can't be set at the same time, because it is unclear what should happen if both preferences are active for one given UID. Therefore, it needs a parameter for ConnectivityService to specify which preference is prior to others. In this commit: 1. Adds a pair of methods with parcelable parameter, which currently includes netId, UID range array and subsidiary priority. 2. The subsidiary priority will be used to adjust the original IP rule priority. UID ranges can applies to different network with different subsidiary priority. But a single UID should not apply to multiple networks with the same subsidiary priority. 3. The possible value of subsidiary priority for physical and unreachable networks is 0-999. 0 is the highest priority. 0 is also the default value. Virtual network supports only the default value. 4. Netd and its tests reference to latest AIDL version (unstable). Bug: 182460808 Test: m; flash; cd system/netd/; atest Test: atest FrameworksNetTests Test: atest HostsideVpnTests Original-Change: https://android-review.googlesource.com/1714116 Merged-In: I94e8830d0a21ffcca17757fe4783a4be9438c8b4 Change-Id: I94e8830d0a21ffcca17757fe4783a4be9438c8b4
-rw-r--r--server/Android.bp8
-rw-r--r--server/NetdNativeService.cpp21
-rw-r--r--server/NetdNativeService.h4
-rw-r--r--server/Network.cpp49
-rw-r--r--server/Network.h20
-rw-r--r--server/NetworkController.cpp47
-rw-r--r--server/NetworkController.h6
-rw-r--r--server/PhysicalNetwork.cpp26
-rw-r--r--server/PhysicalNetwork.h5
-rw-r--r--server/RouteController.cpp203
-rw-r--r--server/RouteController.h31
-rw-r--r--server/UidRanges.h4
-rw-r--r--server/UnreachableNetwork.cpp22
-rw-r--r--server/UnreachableNetwork.h5
-rw-r--r--server/VirtualNetwork.cpp25
-rw-r--r--server/VirtualNetwork.h5
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl2
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl41
-rw-r--r--server/binder/android/net/INetd.aidl28
-rw-r--r--server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl41
-rw-r--r--tests/Android.bp4
-rw-r--r--tests/binder_test.cpp340
22 files changed, 734 insertions, 203 deletions
diff --git a/server/Android.bp b/server/Android.bp
index cf0a29c5..82ee1d03 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -68,6 +68,8 @@ aidl_interface {
"binder/android/net/TetherOffloadRuleParcel.aidl",
"binder/android/net/TetherStatsParcel.aidl",
"binder/android/net/UidRangeParcel.aidl",
+ // Add new AIDL classes in android.net.netd.aidl to consist with other network modules.
+ "binder/android/net/netd/aidl/**/*.aidl",
],
backend: {
cpp: {
@@ -219,7 +221,7 @@ cc_library_static {
"libqtaguid",
"libssl",
"libsysutils",
- "netd_aidl_interface-V6-cpp",
+ "netd_aidl_interface-V7-cpp",
"netd_event_listener_interface-V1-cpp",
],
aidl: {
@@ -262,7 +264,7 @@ cc_binary {
"libselinux",
"libsysutils",
"libutils",
- "netd_aidl_interface-V6-cpp",
+ "netd_aidl_interface-V7-cpp",
"netd_event_listener_interface-V1-cpp",
"oemnetd_aidl_interface-cpp",
],
@@ -360,7 +362,7 @@ cc_test {
"libnetd_server",
"libnetd_test_tun_interface",
"libqtaguid",
- "netd_aidl_interface-V6-cpp",
+ "netd_aidl_interface-V7-cpp",
"netd_event_listener_interface-V1-cpp",
],
shared_libs: [
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 05c515d3..1f5dc976 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -56,6 +56,7 @@ using android::net::NativeNetworkType;
using android::net::TetherOffloadRuleParcel;
using android::net::TetherStatsParcel;
using android::net::UidRangeParcel;
+using android::net::netd::aidl::NativeUidRangeConfig;
using android::netdutils::DumpWriter;
using android::netdutils::ScopedIndent;
using android::os::ParcelFileDescriptor;
@@ -400,7 +401,8 @@ binder::Status NetdNativeService::networkAddUidRanges(
int32_t netId, const std::vector<UidRangeParcel>& uidRangeArray) {
// NetworkController::addUsersToNetwork is thread-safe.
ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray));
+ int ret = gCtls->netCtrl.addUsersToNetwork(netId, UidRanges(uidRangeArray),
+ UidRanges::DEFAULT_SUB_PRIORITY);
return statusFromErrcode(ret);
}
@@ -408,7 +410,22 @@ binder::Status NetdNativeService::networkRemoveUidRanges(
int32_t netId, const std::vector<UidRangeParcel>& uidRangeArray) {
// NetworkController::removeUsersFromNetwork is thread-safe.
ENFORCE_NETWORK_STACK_PERMISSIONS();
- int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, UidRanges(uidRangeArray));
+ int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, UidRanges(uidRangeArray),
+ UidRanges::DEFAULT_SUB_PRIORITY);
+ return statusFromErrcode(ret);
+}
+
+binder::Status NetdNativeService::networkAddUidRangesParcel(const NativeUidRangeConfig& config) {
+ ENFORCE_NETWORK_STACK_PERMISSIONS();
+ int ret = gCtls->netCtrl.addUsersToNetwork(config.netId, UidRanges(config.uidRanges),
+ config.subPriority);
+ return statusFromErrcode(ret);
+}
+
+binder::Status NetdNativeService::networkRemoveUidRangesParcel(const NativeUidRangeConfig& config) {
+ ENFORCE_NETWORK_STACK_PERMISSIONS();
+ int ret = gCtls->netCtrl.removeUsersFromNetwork(config.netId, UidRanges(config.uidRanges),
+ config.subPriority);
return statusFromErrcode(ret);
}
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 1e995ef2..9779f368 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -74,6 +74,10 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
const std::vector<UidRangeParcel>& uids) override;
binder::Status networkRemoveUidRanges(int32_t netId,
const std::vector<UidRangeParcel>& uids) override;
+ binder::Status networkAddUidRangesParcel(
+ const netd::aidl::NativeUidRangeConfig& uidRangesConfig) override;
+ binder::Status networkRemoveUidRangesParcel(
+ const netd::aidl::NativeUidRangeConfig& uidRangesConfig) override;
binder::Status networkRejectNonSecureVpn(bool enable,
const std::vector<UidRangeParcel>& uids) override;
binder::Status networkAddRouteParcel(int32_t netId, const RouteInfoParcel& route) override;
diff --git a/server/Network.cpp b/server/Network.cpp
index cba9edf5..3796cb6f 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -70,22 +70,53 @@ std::string Network::toString() const {
return repr.str();
}
-bool Network::appliesToUser(uid_t uid) const {
- return mUidRanges.hasUid(uid);
+// Check if the user has been added to this network. If yes, the highest priority of matching
+// setting is returned by subPriority. Thus caller can make choice among several matching
+// networks.
+bool Network::appliesToUser(uid_t uid, uint32_t* subPriority) const {
+ for (const auto& [priority, uidRanges] : mUidRangeMap) {
+ if (uidRanges.hasUid(uid)) {
+ *subPriority = priority;
+ return true;
+ }
+ }
+ return false;
+}
+
+void Network::addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
+ auto iter = mUidRangeMap.find(subPriority);
+ if (iter != mUidRangeMap.end()) {
+ iter->second.add(uidRanges);
+ } else {
+ mUidRangeMap[subPriority] = uidRanges;
+ }
}
-bool Network::hasInvalidUidRanges(const UidRanges& uidRanges) const {
+void Network::removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority) {
+ auto iter = mUidRangeMap.find(subPriority);
+ if (iter != mUidRangeMap.end()) {
+ iter->second.remove(uidRanges);
+ if (iter->second.empty()) {
+ mUidRangeMap.erase(subPriority);
+ }
+ } else {
+ ALOGW("uidRanges with priority %u not found", subPriority);
+ }
+}
+
+bool Network::canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const {
if (uidRanges.overlapsSelf()) {
ALOGE("uid range %s overlaps self", uidRanges.toString().c_str());
- return true;
+ return false;
}
- if (uidRanges.overlaps(mUidRanges)) {
- ALOGE("uid range %s overlaps %s", uidRanges.toString().c_str(),
- mUidRanges.toString().c_str());
- return true;
+ auto iter = mUidRangeMap.find(subPriority);
+ if (iter != mUidRangeMap.end() && uidRanges.overlaps(iter->second)) {
+ ALOGE("uid range %s overlaps priority %u %s", uidRanges.toString().c_str(), subPriority,
+ iter->second.toString().c_str());
+ return false;
}
- return false;
+ return true;
}
bool Network::isSecure() const {
diff --git a/server/Network.h b/server/Network.h
index d5110d02..bec37513 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -24,6 +24,8 @@
namespace android::net {
+typedef std::map<uint32_t, UidRanges> UidRangeMap;
+
// A Network represents a collection of interfaces participating as a single administrative unit.
class Network {
public:
@@ -44,22 +46,30 @@ public:
[[nodiscard]] int clearInterfaces();
std::string toString() const;
- bool appliesToUser(uid_t uid) const;
- [[nodiscard]] virtual int addUsers(const UidRanges&) { return -EINVAL; };
- [[nodiscard]] virtual int removeUsers(const UidRanges&) { return -EINVAL; };
+ bool appliesToUser(uid_t uid, uint32_t* subPriority) const;
+ [[nodiscard]] virtual int addUsers(const UidRanges&, uint32_t /*subPriority*/) {
+ return -EINVAL;
+ };
+ [[nodiscard]] virtual int removeUsers(const UidRanges&, uint32_t /*subPriority*/) {
+ return -EINVAL;
+ };
bool isSecure() const;
virtual bool isPhysical() { return false; }
virtual bool isUnreachable() { return false; }
virtual bool isVirtual() { return false; }
virtual bool canAddUsers() { return false; }
+ virtual bool isValidSubPriority(uint32_t /*priority*/) { return false; }
+ virtual void addToUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
+ virtual void removeFromUidRangeMap(const UidRanges& uidRanges, uint32_t subPriority);
protected:
explicit Network(unsigned netId, bool mSecure = false);
- bool hasInvalidUidRanges(const UidRanges& uidRanges) const;
+ bool canAddUidRanges(const UidRanges& uidRanges, uint32_t subPriority) const;
const unsigned mNetId;
std::set<std::string> mInterfaces;
- UidRanges mUidRanges;
+ // Each subsidiary priority maps to a set of UID ranges of a feature.
+ std::map<uint32_t, UidRanges> mUidRangeMap;
const bool mSecure;
private:
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index ff52db5b..db96dea4 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -616,22 +616,24 @@ int isWrongNetworkForUidRanges(unsigned netId, Network* network) {
} // namespace
-int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
+int NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority) {
ScopedWLock lock(mRWLock);
Network* network = getNetworkLocked(netId);
if (int ret = isWrongNetworkForUidRanges(netId, network)) {
return ret;
}
- return network->addUsers(uidRanges);
+ return network->addUsers(uidRanges, subPriority);
}
-int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
+int NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority) {
ScopedWLock lock(mRWLock);
Network* network = getNetworkLocked(netId);
if (int ret = isWrongNetworkForUidRanges(netId, network)) {
return ret;
}
- return network->removeUsers(uidRanges);
+ return network->removeUsers(uidRanges, subPriority);
}
int NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
@@ -776,30 +778,32 @@ Network* NetworkController::getNetworkLocked(unsigned netId) const {
}
VirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
+ uint32_t subPriority;
for (const auto& [_, network] : mNetworks) {
- if (network->isVirtual() && network->appliesToUser(uid)) {
+ if (network->isVirtual() && network->appliesToUser(uid, &subPriority)) {
return static_cast<VirtualNetwork*>(network);
}
}
return nullptr;
}
+// Returns a network with the highest subsidiary priority among physical and unreachable networks
+// that applies to uid. For a single subsidiary priority, an uid should belong to only one network.
+// If the uid apply to different network with the same priority at the same time, the behavior is
+// undefined. That is a configuration error.
Network* NetworkController::getPhysicalOrUnreachableNetworkForUserLocked(uid_t uid) const {
- // OEM-paid network take precedence over the unreachable network.
- 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 network;
+ Network* bestNetwork = nullptr;
+ unsigned bestSubPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
+ for (const auto& [netId, network] : mNetworks) {
+ uint32_t subPriority;
+ if (!network->isPhysical() && !network->isUnreachable()) continue;
+ if (!network->appliesToUser(uid, &subPriority)) continue;
+ if (subPriority < bestSubPriority) {
+ bestNetwork = network;
+ bestSubPriority = subPriority;
}
}
-
- auto iter = mNetworks.find(UNREACHABLE_NET_ID);
- if (iter != mNetworks.end() && iter->second->appliesToUser(uid)) {
- return iter->second;
- }
- return nullptr;
+ return bestNetwork;
}
Permission NetworkController::getPermissionForUserLocked(uid_t uid) const {
@@ -827,8 +831,9 @@ int NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) c
return 0;
}
// If the UID wants to use a VPN, it can do so if and only if the VPN applies to the UID.
+ uint32_t subPriority;
if (network->isVirtual()) {
- return network->appliesToUser(uid) ? 0 : -EPERM;
+ return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM;
}
// If a VPN applies to the UID, and the VPN is secure (i.e., not bypassable), then the UID can
// only select a different network if it has the ability to protect its sockets.
@@ -839,12 +844,12 @@ int NetworkController::checkUserNetworkAccessLocked(uid_t uid, unsigned netId) c
}
// 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)) {
+ if (network->isPhysical() && network->appliesToUser(uid, &subPriority)) {
return 0;
}
// Only apps that are configured as "no default network" can use the unreachable network.
if (network->isUnreachable()) {
- return network->appliesToUser(uid) ? 0 : -EPERM;
+ return network->appliesToUser(uid, &subPriority) ? 0 : -EPERM;
}
// 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
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 46302252..a61ac39f 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -119,8 +119,10 @@ public:
[[nodiscard]] int setPermissionForNetworks(Permission permission,
const std::vector<unsigned>& netIds);
- [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges);
- [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges);
+ [[nodiscard]] int addUsersToNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority);
+ [[nodiscard]] int removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges,
+ uint32_t subPriority);
// |nexthop| can be NULL (to indicate a directly-connected route), "unreachable" (to indicate a
// route that's blocked), "throw" (to indicate the lack of a match), or a regular IP address.
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index 894d56ab..7b9a19a1 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -158,32 +158,35 @@ int PhysicalNetwork::removeAsDefault() {
return 0;
}
-int PhysicalNetwork::addUsers(const UidRanges& uidRanges) {
- if (hasInvalidUidRanges(uidRanges)) {
+int PhysicalNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
return -EINVAL;
}
for (const std::string& interface : mInterfaces) {
- int ret = RouteController::addUsersToPhysicalNetwork(mNetId, interface.c_str(), uidRanges);
+ int ret = RouteController::addUsersToPhysicalNetwork(mNetId, interface.c_str(),
+ {{subPriority, uidRanges}});
if (ret) {
ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- mUidRanges.add(uidRanges);
+ addToUidRangeMap(uidRanges, subPriority);
return 0;
}
-int PhysicalNetwork::removeUsers(const UidRanges& uidRanges) {
+int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority)) return -EINVAL;
+
for (const std::string& interface : mInterfaces) {
int ret = RouteController::removeUsersFromPhysicalNetwork(mNetId, interface.c_str(),
- uidRanges);
+ {{subPriority, uidRanges}});
if (ret) {
ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- mUidRanges.remove(uidRanges);
+ removeFromUidRangeMap(uidRanges, subPriority);
return 0;
}
@@ -192,7 +195,7 @@ int PhysicalNetwork::addInterface(const std::string& interface) {
return 0;
}
if (int ret = RouteController::addInterfaceToPhysicalNetwork(mNetId, interface.c_str(),
- mPermission, mUidRanges)) {
+ mPermission, mUidRangeMap)) {
ALOGE("failed to add interface %s to netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -219,7 +222,7 @@ int PhysicalNetwork::removeInterface(const std::string& interface) {
// to find the interface index in the cache in cases where the interface is already gone
// (e.g. bt-pan).
if (int ret = RouteController::removeInterfaceFromPhysicalNetwork(mNetId, interface.c_str(),
- mPermission, mUidRanges)) {
+ mPermission, mUidRangeMap)) {
ALOGE("failed to remove interface %s from netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -227,4 +230,9 @@ int PhysicalNetwork::removeInterface(const std::string& interface) {
return 0;
}
+bool PhysicalNetwork::isValidSubPriority(uint32_t priority) {
+ return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
+ priority <= UidRanges::LOWEST_SUB_PRIORITY;
+}
+
} // namespace android::net
diff --git a/server/PhysicalNetwork.h b/server/PhysicalNetwork.h
index df2bd225..d9461b2e 100644
--- a/server/PhysicalNetwork.h
+++ b/server/PhysicalNetwork.h
@@ -42,8 +42,8 @@ class PhysicalNetwork : public Network {
[[nodiscard]] int addAsDefault();
[[nodiscard]] int removeAsDefault();
- [[nodiscard]] int addUsers(const UidRanges& uidRanges) override;
- [[nodiscard]] int removeUsers(const UidRanges& uidRanges) override;
+ [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+ [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
bool isPhysical() override { return true; }
bool canAddUsers() override { return true; }
@@ -53,6 +53,7 @@ class PhysicalNetwork : public Network {
[[nodiscard]] int removeInterface(const std::string& interface) override;
int destroySocketsLackingPermission(Permission permission);
void invalidateRouteCache(const std::string& interface);
+ bool isValidSubPriority(uint32_t priority) override;
Delegate* const mDelegate;
Permission mPermission;
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 666a88a7..ba305e69 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -27,14 +27,11 @@
#include <map>
-#define LOG_TAG "Netd"
-
#include "DummyNetwork.h"
#include "Fwmark.h"
#include "NetdConstants.h"
#include "NetlinkCommands.h"
#include "OffloadUtils.h"
-#include "UidRanges.h"
#include <android-base/file.h>
#include <android-base/stringprintf.h>
@@ -495,7 +492,7 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
// have, if they are subject to this VPN, their traffic has to go through it. Allows the traffic to
// bypass the VPN if the protectedFromVpn bit is set.
[[nodiscard]] static int modifyVpnUidRangeRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
- bool secure, bool add) {
+ uint32_t subPriority, bool secure, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -513,8 +510,8 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
mask.explicitlySelected = true;
}
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority, table, fwmark.intValue,
- mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, priority + subPriority, table,
+ fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
// A rule to allow system apps to send traffic over this VPN even if they are not part of the target
@@ -548,7 +545,7 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
// modifyNetworkPermission().
[[nodiscard]] static int modifyExplicitNetworkRule(unsigned netId, uint32_t table,
Permission permission, uid_t uidStart,
- uid_t uidEnd, bool add) {
+ uid_t uidEnd, uint32_t subPriority, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -561,8 +558,9 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
fwmark.permission = permission;
mask.permission = permission;
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_EXPLICIT_NETWORK, table,
- fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ RULE_PRIORITY_EXPLICIT_NETWORK + subPriority, table, fwmark.intValue,
+ mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
// A rule to route traffic based on a chosen outgoing interface.
@@ -571,7 +569,7 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
// the outgoing interface (typically for link-local communications).
[[nodiscard]] static int modifyOutputInterfaceRules(const char* interface, uint32_t table,
Permission permission, uid_t uidStart,
- uid_t uidEnd, bool add) {
+ uid_t uidEnd, uint32_t subPriority, bool add) {
Fwmark fwmark;
Fwmark mask;
@@ -589,8 +587,9 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
}
}
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_OUTPUT_INTERFACE, table,
- fwmark.intValue, mask.intValue, IIF_LOOPBACK, interface, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ RULE_PRIORITY_OUTPUT_INTERFACE + subPriority, table, fwmark.intValue,
+ mask.intValue, IIF_LOOPBACK, interface, uidStart, uidEnd);
}
// A rule to route traffic based on the chosen network.
@@ -670,7 +669,8 @@ int RouteController::modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId
// Add rules to lookup the local network when specified explicitly or otherwise.
[[nodiscard]] static int addLocalNetworkRules(unsigned localNetId) {
if (int ret = modifyExplicitNetworkRule(localNetId, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
- INVALID_UID, INVALID_UID, ACTION_ADD)) {
+ INVALID_UID, INVALID_UID,
+ UidRanges::DEFAULT_SUB_PRIORITY, ACTION_ADD)) {
return ret;
}
@@ -701,8 +701,9 @@ int RouteController::configureDummyNetwork() {
return -errno;
}
- if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE,
- INVALID_UID, INVALID_UID, ACTION_ADD))) {
+ if ((ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, INVALID_UID,
+ INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
+ ACTION_ADD))) {
ALOGE("Can't create oif rules for %s: %s", interface, strerror(-ret));
return ret;
}
@@ -735,11 +736,13 @@ int RouteController::configureDummyNetwork() {
}
maybeModifyQdiscClsact(interface, add);
return modifyOutputInterfaceRules(interface, ROUTE_TABLE_LOCAL_NETWORK, PERMISSION_NONE,
- INVALID_UID, INVALID_UID, add);
+ INVALID_UID, INVALID_UID, UidRanges::DEFAULT_SUB_PRIORITY,
+ add);
}
[[nodiscard]] static int modifyUidNetworkRule(unsigned netId, uint32_t table, uid_t uidStart,
- uid_t uidEnd, bool add, bool explicitSelect) {
+ uid_t uidEnd, uint32_t subPriority, bool add,
+ bool explicitSelect) {
if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
ALOGE("modifyUidNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
return -EUSERS;
@@ -759,14 +762,14 @@ int RouteController::configureDummyNetwork() {
mask.permission = PERMISSION_NONE;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- explicitSelect ? RULE_PRIORITY_UID_EXPLICIT_NETWORK
- : RULE_PRIORITY_UID_IMPLICIT_NETWORK,
+ explicitSelect ? (RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority)
+ : (RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority),
table, fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart,
uidEnd);
}
[[nodiscard]] static int modifyUidDefaultNetworkRule(uint32_t table, uid_t uidStart, uid_t uidEnd,
- bool add) {
+ uint32_t subPriority, bool add) {
if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
ALOGE("modifyUidDefaultNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
return -EUSERS;
@@ -782,28 +785,34 @@ int RouteController::configureDummyNetwork() {
fwmark.permission = PERMISSION_NONE;
mask.permission = PERMISSION_NONE;
- return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_UID_DEFAULT_NETWORK, table,
- fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ RULE_PRIORITY_UID_DEFAULT_NETWORK + subPriority, table, fwmark.intValue,
+ mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
/* static */
int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges, Permission permission,
+ const UidRangeMap& uidRangeMap, Permission permission,
bool add, bool modifyNonUidBasedRules) {
uint32_t table = getRouteTableForInterface(interface);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
- for (const UidRangeParcel& range : uidRanges.getRanges()) {
- if (int ret = modifyUidNetworkRule(netId, table, range.start, range.stop, add, EXPLICIT)) {
- return ret;
- }
- if (int ret = modifyUidNetworkRule(netId, table, range.start, range.stop, add, IMPLICIT)) {
- return ret;
- }
- if (int ret = modifyUidDefaultNetworkRule(table, range.start, range.stop, add)) {
- return ret;
+ for (const auto& [subPriority, uidRanges] : uidRangeMap) {
+ for (const UidRangeParcel& range : uidRanges.getRanges()) {
+ if (int ret = modifyUidNetworkRule(netId, table, range.start, range.stop, subPriority,
+ add, EXPLICIT)) {
+ return ret;
+ }
+ if (int ret = modifyUidNetworkRule(netId, table, range.start, range.stop, subPriority,
+ add, IMPLICIT)) {
+ return ret;
+ }
+ if (int ret = modifyUidDefaultNetworkRule(table, range.start, range.stop, subPriority,
+ add)) {
+ return ret;
+ }
}
}
@@ -816,11 +825,11 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
return ret;
}
if (int ret = modifyExplicitNetworkRule(netId, table, permission, INVALID_UID, INVALID_UID,
- add)) {
+ UidRanges::DEFAULT_SUB_PRIORITY, add)) {
return ret;
}
if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
- add)) {
+ UidRanges::DEFAULT_SUB_PRIORITY, add)) {
return ret;
}
@@ -851,7 +860,8 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
}
[[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd,
- bool add, bool explicitSelect) {
+ uint32_t subPriority, bool add,
+ bool explicitSelect) {
if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
ALOGE("modifyUidUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
return -EUSERS;
@@ -871,15 +881,16 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
mask.permission = PERMISSION_NONE;
return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
- explicitSelect ? RULE_PRIORITY_UID_EXPLICIT_NETWORK
- : RULE_PRIORITY_UID_IMPLICIT_NETWORK,
+ explicitSelect ? (RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority)
+ : (RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority),
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) {
+[[nodiscard]] static int modifyUidDefaultUnreachableRule(uid_t uidStart, uid_t uidEnd,
+ uint32_t subPriority, bool add) {
if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) {
- ALOGE("modifyUidDefaultNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
+ ALOGE("modifyUidDefaultUnreachableRule, invalid UIDs (%u, %u)", uidStart, uidEnd);
return -EUSERS;
}
@@ -893,22 +904,28 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
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);
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+ RULE_PRIORITY_UID_DEFAULT_UNREACHABLE + subPriority, FR_ACT_UNREACHABLE,
+ RT_TABLE_UNSPEC, fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE,
+ uidStart, uidEnd);
}
-int RouteController::modifyUnreachableNetwork(unsigned netId, const UidRanges& uidRanges,
+int RouteController::modifyUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap,
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;
+ for (const auto& [subPriority, uidRanges] : uidRangeMap) {
+ for (const UidRangeParcel& range : uidRanges.getRanges()) {
+ if (int ret = modifyUidUnreachableRule(netId, range.start, range.stop, subPriority, add,
+ EXPLICIT)) {
+ return ret;
+ }
+ if (int ret = modifyUidUnreachableRule(netId, range.start, range.stop, subPriority, add,
+ IMPLICIT)) {
+ return ret;
+ }
+ if (int ret = modifyUidDefaultUnreachableRule(range.start, range.stop, subPriority,
+ add)) {
+ return ret;
+ }
}
}
@@ -933,24 +950,27 @@ int RouteController::modifyUnreachableNetwork(unsigned netId, const UidRanges& u
}
int RouteController::modifyVirtualNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges, bool secure, bool add,
+ const UidRangeMap& uidRangeMap, bool secure, bool add,
bool modifyNonUidBasedRules) {
uint32_t table = getRouteTableForInterface(interface);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
}
- for (const UidRangeParcel& range : uidRanges.getRanges()) {
- if (int ret = modifyVpnUidRangeRule(table, range.start, range.stop, secure, add)) {
- return ret;
- }
- if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, range.start,
- range.stop, add)) {
- return ret;
- }
- if (int ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, range.start,
- range.stop, add)) {
- return ret;
+ for (const auto& [subPriority, uidRanges] : uidRangeMap) {
+ for (const UidRangeParcel& range : uidRanges.getRanges()) {
+ if (int ret = modifyVpnUidRangeRule(table, range.start, range.stop, subPriority, secure,
+ add)) {
+ return ret;
+ }
+ if (int ret = modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, range.start,
+ range.stop, subPriority, add)) {
+ return ret;
+ }
+ if (int ret = modifyOutputInterfaceRules(interface, table, PERMISSION_NONE, range.start,
+ range.stop, subPriority, add)) {
+ return ret;
+ }
}
}
@@ -964,7 +984,8 @@ int RouteController::modifyVirtualNetwork(unsigned netId, const char* interface,
if (int ret = modifyVpnSystemPermissionRule(netId, table, secure, add)) {
return ret;
}
- return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT, add);
+ return modifyExplicitNetworkRule(netId, table, PERMISSION_NONE, UID_ROOT, UID_ROOT,
+ UidRanges::DEFAULT_SUB_PRIORITY, add);
}
return 0;
@@ -1166,8 +1187,8 @@ int RouteController::removeInterfaceFromLocalNetwork(unsigned netId, const char*
int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
Permission permission,
- const UidRanges& uidRanges) {
- if (int ret = modifyPhysicalNetwork(netId, interface, uidRanges, permission, ACTION_ADD,
+ const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_ADD,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1178,8 +1199,8 @@ int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* i
int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const char* interface,
Permission permission,
- const UidRanges& uidRanges) {
- if (int ret = modifyPhysicalNetwork(netId, interface, uidRanges, permission, ACTION_DEL,
+ const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_DEL,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1195,8 +1216,8 @@ int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const ch
}
int RouteController::addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges) {
- if (int ret = modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,
+ bool secure, const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1205,8 +1226,9 @@ int RouteController::addInterfaceToVirtualNetwork(unsigned netId, const char* in
}
int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges) {
- if (int ret = modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_DEL,
+ bool secure,
+ const UidRangeMap& uidRangeMap) {
+ if (int ret = modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
@@ -1220,13 +1242,15 @@ int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const cha
int RouteController::modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
Permission newPermission) {
- UidRanges noUidRanges;
+ // Physical network rules either use permission bits or UIDs, but not both.
+ // So permission changes don't affect any UID-based rules.
+ UidRangeMap emptyUidRangeMap;
// Add the new rules before deleting the old ones, to avoid race conditions.
- if (int ret = modifyPhysicalNetwork(netId, interface, noUidRanges, newPermission, ACTION_ADD,
- MODIFY_NON_UID_BASED_RULES)) {
+ if (int ret = modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, newPermission,
+ ACTION_ADD, MODIFY_NON_UID_BASED_RULES)) {
return ret;
}
- return modifyPhysicalNetwork(netId, interface, noUidRanges, oldPermission, ACTION_DEL,
+ return modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, oldPermission, ACTION_DEL,
MODIFY_NON_UID_BASED_RULES);
}
@@ -1239,14 +1263,14 @@ int RouteController::removeUsersFromRejectNonSecureNetworkRule(const UidRanges&
}
int RouteController::addUsersToVirtualNetwork(unsigned netId, const char* interface, bool secure,
- const UidRanges& uidRanges) {
- return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,
+ const UidRangeMap& uidRangeMap) {
+ return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_ADD,
!MODIFY_NON_UID_BASED_RULES);
}
int RouteController::removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges) {
- return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_DEL,
+ bool secure, const UidRangeMap& uidRangeMap) {
+ return modifyVirtualNetwork(netId, interface, uidRangeMap, secure, ACTION_DEL,
!MODIFY_NON_UID_BASED_RULES);
}
@@ -1297,23 +1321,24 @@ int RouteController::removeVirtualNetworkFallthrough(unsigned vpnNetId,
}
int RouteController::addUsersToPhysicalNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges) {
- return modifyPhysicalNetwork(netId, interface, uidRanges, PERMISSION_NONE, ACTION_ADD,
+ const UidRangeMap& uidRangeMap) {
+ return modifyPhysicalNetwork(netId, interface, uidRangeMap, PERMISSION_NONE, ACTION_ADD,
!MODIFY_NON_UID_BASED_RULES);
}
int RouteController::removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges) {
- return modifyPhysicalNetwork(netId, interface, uidRanges, PERMISSION_NONE, ACTION_DEL,
+ const UidRangeMap& uidRangeMap) {
+ return modifyPhysicalNetwork(netId, interface, uidRangeMap, PERMISSION_NONE, ACTION_DEL,
!MODIFY_NON_UID_BASED_RULES);
}
-int RouteController::addUsersToUnreachableNetwork(unsigned netId, const UidRanges& uidRanges) {
- return modifyUnreachableNetwork(netId, uidRanges, ACTION_ADD);
+int RouteController::addUsersToUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap) {
+ return modifyUnreachableNetwork(netId, uidRangeMap, ACTION_ADD);
}
-int RouteController::removeUsersFromUnreachableNetwork(unsigned netId, const UidRanges& uidRanges) {
- return modifyUnreachableNetwork(netId, uidRanges, ACTION_DEL);
+int RouteController::removeUsersFromUnreachableNetwork(unsigned netId,
+ const UidRangeMap& uidRangeMap) {
+ return modifyUnreachableNetwork(netId, uidRangeMap, ACTION_DEL);
}
// Protects sInterfaceToTable.
diff --git a/server/RouteController.h b/server/RouteController.h
index 7f1f960f..38d2d621 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -17,6 +17,7 @@
#pragma once
#include "NetdConstants.h" // IptablesTarget
+#include "Network.h" // UidRangeMap
#include "Permission.h"
#include <android-base/thread_annotations.h>
@@ -107,26 +108,28 @@ public:
[[nodiscard]] static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
Permission permission,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeInterfaceFromPhysicalNetwork(unsigned netId,
const char* interface,
Permission permission,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges);
+ bool secure,
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeInterfaceFromVirtualNetwork(unsigned netId,
const char* interface, bool secure,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
Permission newPermission);
[[nodiscard]] static int addUsersToVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges);
+ bool secure, const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeUsersFromVirtualNetwork(unsigned netId, const char* interface,
- bool secure, const UidRanges& uidRanges);
+ bool secure,
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges);
[[nodiscard]] static int removeUsersFromRejectNonSecureNetworkRule(const UidRanges& uidRanges);
@@ -158,16 +161,16 @@ public:
Permission permission);
[[nodiscard]] static int addUsersToPhysicalNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int addUsersToUnreachableNetwork(unsigned netId,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
[[nodiscard]] static int removeUsersFromUnreachableNetwork(unsigned netId,
- const UidRanges& uidRanges);
+ const UidRangeMap& uidRangeMap);
// For testing.
static int (*iptablesRestoreCommandFunction)(IptablesTarget, const std::string&,
@@ -187,9 +190,9 @@ private:
static uint32_t getRouteTableForInterface(const char *interface) EXCLUDES(sInterfaceToTableLock);
static int modifyDefaultNetwork(uint16_t action, const char* interface, Permission permission);
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);
+ const UidRangeMap& uidRangeMap, Permission permission,
+ bool add, bool modifyNonUidBasedRules);
+ static int modifyUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap, bool add);
static int modifyRoute(uint16_t action, uint16_t flags, const char* interface,
const char* destination, const char* nexthop, TableType tableType,
int mtu);
@@ -198,7 +201,7 @@ private:
static int modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId,
const char* physicalInterface, Permission permission);
static int modifyVirtualNetwork(unsigned netId, const char* interface,
- const UidRanges& uidRanges, bool secure, bool add,
+ const UidRangeMap& uidRangeMap, bool secure, bool add,
bool modifyNonUidBasedRules);
static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock);
};
diff --git a/server/UidRanges.h b/server/UidRanges.h
index f3223905..99e7a99d 100644
--- a/server/UidRanges.h
+++ b/server/UidRanges.h
@@ -28,6 +28,9 @@ namespace net {
class UidRanges {
public:
+ static constexpr int DEFAULT_SUB_PRIORITY = 0;
+ static constexpr int LOWEST_SUB_PRIORITY = 999;
+
UidRanges() {}
UidRanges(const std::vector<android::net::UidRangeParcel>& ranges);
@@ -44,6 +47,7 @@ public:
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:
// a utility to check if two UidRangeParcels have uid overlap.
diff --git a/server/UnreachableNetwork.cpp b/server/UnreachableNetwork.cpp
index b17c9981..2f801f0c 100644
--- a/server/UnreachableNetwork.cpp
+++ b/server/UnreachableNetwork.cpp
@@ -26,29 +26,37 @@ 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)) {
+int UnreachableNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
return -EINVAL;
}
- int ret = RouteController::addUsersToUnreachableNetwork(mNetId, uidRanges);
+ int ret = RouteController::addUsersToUnreachableNetwork(mNetId, {{subPriority, uidRanges}});
if (ret) {
ALOGE("failed to add users to unreachable network");
return ret;
}
- mUidRanges.add(uidRanges);
+ addToUidRangeMap(uidRanges, subPriority);
return 0;
}
-int UnreachableNetwork::removeUsers(const UidRanges& uidRanges) {
- int ret = RouteController::removeUsersFromUnreachableNetwork(mNetId, uidRanges);
+int UnreachableNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority)) return -EINVAL;
+
+ int ret =
+ RouteController::removeUsersFromUnreachableNetwork(mNetId, {{subPriority, uidRanges}});
if (ret) {
ALOGE("failed to remove users from unreachable network");
return ret;
}
- mUidRanges.remove(uidRanges);
+ removeFromUidRangeMap(uidRanges, subPriority);
return 0;
}
+bool UnreachableNetwork::isValidSubPriority(uint32_t priority) {
+ return priority >= UidRanges::DEFAULT_SUB_PRIORITY &&
+ priority <= UidRanges::LOWEST_SUB_PRIORITY;
+}
+
} // namespace net
} // namespace android
diff --git a/server/UnreachableNetwork.h b/server/UnreachableNetwork.h
index a80f3f39..f1547d60 100644
--- a/server/UnreachableNetwork.h
+++ b/server/UnreachableNetwork.h
@@ -23,13 +23,14 @@ 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;
+ [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+ [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
bool isUnreachable() override { return true; }
bool canAddUsers() override { return true; }
private:
std::string getTypeString() const override { return "UNREACHABLE"; };
+ bool isValidSubPriority(uint32_t priority) override;
};
} // namespace android::net \ No newline at end of file
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 93f4c3e8..1906e208 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -31,33 +31,35 @@ VirtualNetwork::VirtualNetwork(unsigned netId, bool secure) : Network(netId, sec
VirtualNetwork::~VirtualNetwork() {}
-int VirtualNetwork::addUsers(const UidRanges& uidRanges) {
- if (hasInvalidUidRanges(uidRanges)) {
+int VirtualNetwork::addUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority) || !canAddUidRanges(uidRanges, subPriority)) {
return -EINVAL;
}
for (const std::string& interface : mInterfaces) {
int ret = RouteController::addUsersToVirtualNetwork(mNetId, interface.c_str(), mSecure,
- uidRanges);
+ {{subPriority, uidRanges}});
if (ret) {
ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- mUidRanges.add(uidRanges);
+ addToUidRangeMap(uidRanges, subPriority);
return 0;
}
-int VirtualNetwork::removeUsers(const UidRanges& uidRanges) {
+int VirtualNetwork::removeUsers(const UidRanges& uidRanges, uint32_t subPriority) {
+ if (!isValidSubPriority(subPriority)) return -EINVAL;
+
for (const std::string& interface : mInterfaces) {
int ret = RouteController::removeUsersFromVirtualNetwork(mNetId, interface.c_str(), mSecure,
- uidRanges);
+ {{subPriority, uidRanges}});
if (ret) {
ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
}
}
- mUidRanges.remove(uidRanges);
+ removeFromUidRangeMap(uidRanges, subPriority);
return 0;
}
@@ -66,7 +68,7 @@ int VirtualNetwork::addInterface(const std::string& interface) {
return 0;
}
if (int ret = RouteController::addInterfaceToVirtualNetwork(mNetId, interface.c_str(), mSecure,
- mUidRanges)) {
+ mUidRangeMap)) {
ALOGE("failed to add interface %s to VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -79,7 +81,7 @@ int VirtualNetwork::removeInterface(const std::string& interface) {
return 0;
}
if (int ret = RouteController::removeInterfaceFromVirtualNetwork(mNetId, interface.c_str(),
- mSecure, mUidRanges)) {
+ mSecure, mUidRangeMap)) {
ALOGE("failed to remove interface %s from VPN netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -87,5 +89,10 @@ int VirtualNetwork::removeInterface(const std::string& interface) {
return 0;
}
+bool VirtualNetwork::isValidSubPriority(uint32_t priority) {
+ // Only supports default subsidiary permissions.
+ return priority == UidRanges::DEFAULT_SUB_PRIORITY;
+}
+
} // namespace net
} // namespace android
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index ebda7da5..20c9e2c2 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -33,8 +33,8 @@ class VirtualNetwork : public Network {
public:
VirtualNetwork(unsigned netId, bool secure);
virtual ~VirtualNetwork();
- [[nodiscard]] int addUsers(const UidRanges& uidRanges) override;
- [[nodiscard]] int removeUsers(const UidRanges& uidRanges) override;
+ [[nodiscard]] int addUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
+ [[nodiscard]] int removeUsers(const UidRanges& uidRanges, uint32_t subPriority) override;
bool isVirtual() override { return true; }
bool canAddUsers() override { return true; }
@@ -42,6 +42,7 @@ public:
std::string getTypeString() const override { return "VIRTUAL"; };
[[nodiscard]] int addInterface(const std::string& interface) override;
[[nodiscard]] int removeInterface(const std::string& interface) override;
+ bool isValidSubPriority(uint32_t priority) override;
};
} // namespace android::net
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 a7952f28..ec03d86b 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
@@ -145,6 +145,8 @@ interface INetd {
void tetherOffloadSetInterfaceQuota(int ifIndex, long quotaBytes);
android.net.TetherStatsParcel tetherOffloadGetAndClearStats(int ifIndex);
void networkCreate(in android.net.NativeNetworkConfig config);
+ void networkAddUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
+ void networkRemoveUidRangesParcel(in android.net.netd.aidl.NativeUidRangeConfig uidRangesConfig);
const int IPV4 = 4;
const int IPV6 = 6;
const int CONF = 1;
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 00000000..9bb679f1
--- /dev/null
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/netd/aidl/NativeUidRangeConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.netd.aidl;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable NativeUidRangeConfig {
+ int netId;
+ android.net.UidRangeParcel[] uidRanges;
+ int subPriority;
+}
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 8a028314..d6398c12 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -25,6 +25,7 @@ import android.net.TetherConfigParcel;
import android.net.TetherOffloadRuleParcel;
import android.net.TetherStatsParcel;
import android.net.UidRangeParcel;
+import android.net.netd.aidl.NativeUidRangeConfig;
/** {@hide} */
interface INetd {
@@ -1349,4 +1350,31 @@ interface INetd {
* unix errno.
*/
void networkCreate(in NativeNetworkConfig config);
+
+ /**
+ * Adds the specified UID ranges to the specified network. The network can be physical or
+ * virtual. Traffic from the UID ranges will be routed to the network by default. The possible
+ * value of subsidiary priority for physical and unreachable networks is 0-999. 0 is the highest
+ * priority. 0 is also the default value. Virtual network supports only the default value.
+ *
+ * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkAddUidRangesParcel(in NativeUidRangeConfig uidRangesConfig);
+
+ /**
+ * Removes the specified UID ranges from the specified network. The network can be physical or
+ * virtual. Traffic from the UID ranges will no longer be routed to the network by default. The
+ * possible value of subsidiary priority for physical and unreachable networks is 0-999. 0 is
+ * the highest priority. 0 is also the default value. Virtual network supports only the default
+ * value.
+ *
+ * @param NativeUidRangeConfig a parcel contains netId, UID ranges, subsidiary priority, etc.
+ *
+ * @throws ServiceSpecificException in case of failure, with an error code corresponding to the
+ * unix errno.
+ */
+ void networkRemoveUidRangesParcel(in NativeUidRangeConfig uidRangesConfig);
}
diff --git a/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl b/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl
new file mode 100644
index 00000000..99497a86
--- /dev/null
+++ b/server/binder/android/net/netd/aidl/NativeUidRangeConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package android.net.netd.aidl;
+
+import android.net.UidRangeParcel;
+
+/**
+ * The configuration to add or remove UID ranges.
+ *
+ * {@hide}
+ */
+@JavaDerive(toString=true, equals=true)
+@JavaOnlyImmutable
+parcelable NativeUidRangeConfig {
+ /** The network ID of the network to add/remove the ranges to/from. */
+ int netId;
+
+ /** A set of non-overlapping ranges of UIDs. */
+ UidRangeParcel[] uidRanges;
+
+ /**
+ * The priority of this UID range config. 0 is the highest priority; 999 is the lowest priority.
+ * The function of this parameter is to adjust the priority when the same UID is set to
+ * different networks for different features.
+ */
+ int subPriority;
+} \ No newline at end of file
diff --git a/tests/Android.bp b/tests/Android.bp
index 6ae752b8..c5d9bb53 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -52,7 +52,7 @@ cc_test_library {
"libnetutils",
"libsysutils",
"libutils",
- "netd_aidl_interface-V6-cpp",
+ "netd_aidl_interface-V7-cpp",
],
}
@@ -107,7 +107,7 @@ cc_test {
"libnetdbpf",
"libnetdutils",
"libqtaguid",
- "netd_aidl_interface-V6-cpp",
+ "netd_aidl_interface-V7-cpp",
"netd_event_listener_interface-V1-cpp",
"oemnetd_aidl_interface-cpp",
],
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 69d1f9b5..e82285b7 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -109,8 +109,10 @@ using android::net::MarkMaskParcel;
using android::net::NativeNetworkConfig;
using android::net::NativeNetworkType;
using android::net::NativeVpnType;
+using android::net::RULE_PRIORITY_BYPASSABLE_VPN;
using android::net::RULE_PRIORITY_DEFAULT_NETWORK;
using android::net::RULE_PRIORITY_EXPLICIT_NETWORK;
+using android::net::RULE_PRIORITY_OUTPUT_INTERFACE;
using android::net::RULE_PRIORITY_PROHIBIT_NON_VPN;
using android::net::RULE_PRIORITY_SECURE_VPN;
using android::net::RULE_PRIORITY_TETHERING;
@@ -124,6 +126,8 @@ using android::net::TetherOffloadRuleParcel;
using android::net::TetherStatsParcel;
using android::net::TunInterface;
using android::net::UidRangeParcel;
+using android::net::UidRanges;
+using android::net::netd::aidl::NativeUidRangeConfig;
using android::netdutils::IPAddress;
using android::netdutils::ScopedAddrinfo;
using android::netdutils::sSyscalls;
@@ -134,6 +138,7 @@ static const char* IP_RULE_V6 = "-6";
static const int TEST_NETID1 = 65501;
static const int TEST_NETID2 = 65502;
static const int TEST_NETID3 = 65503;
+static const int TEST_NETID4 = 65504;
static const int TEST_DUMP_NETID = 65123;
static const char* DNSMASQ = "dnsmasq";
@@ -142,6 +147,9 @@ static const char* DNSMASQ = "dnsmasq";
static const int TEST_UID1 = 99999;
static const int TEST_UID2 = 99998;
static const int TEST_UID3 = 99997;
+static const int TEST_UID4 = 99996;
+static const int TEST_UID5 = 99995;
+static const int TEST_UID6 = 99994;
constexpr int BASE_UID = AID_USER_OFFSET * 5;
@@ -170,6 +178,7 @@ class NetdBinderTest : public ::testing::Test {
mNetd->networkDestroy(TEST_NETID1);
mNetd->networkDestroy(TEST_NETID2);
mNetd->networkDestroy(TEST_NETID3);
+ mNetd->networkDestroy(TEST_NETID4);
setNetworkForProcess(NETID_UNSET);
// Restore default network
if (mStoredDefaultNetwork >= 0) mNetd->networkSetDefault(mStoredDefaultNetwork);
@@ -182,9 +191,11 @@ class NetdBinderTest : public ::testing::Test {
ASSERT_EQ(0, sTun.init());
ASSERT_EQ(0, sTun2.init());
ASSERT_EQ(0, sTun3.init());
+ ASSERT_EQ(0, sTun4.init());
ASSERT_LE(sTun.name().size(), static_cast<size_t>(IFNAMSIZ));
ASSERT_LE(sTun2.name().size(), static_cast<size_t>(IFNAMSIZ));
ASSERT_LE(sTun3.name().size(), static_cast<size_t>(IFNAMSIZ));
+ ASSERT_LE(sTun4.name().size(), static_cast<size_t>(IFNAMSIZ));
}
static void TearDownTestCase() {
@@ -192,6 +203,7 @@ class NetdBinderTest : public ::testing::Test {
sTun.destroy();
sTun2.destroy();
sTun3.destroy();
+ sTun4.destroy();
}
static void fakeRemoteSocketPair(unique_fd* clientSocket, unique_fd* serverSocket,
@@ -224,11 +236,13 @@ class NetdBinderTest : public ::testing::Test {
static TunInterface sTun;
static TunInterface sTun2;
static TunInterface sTun3;
+ static TunInterface sTun4;
};
TunInterface NetdBinderTest::sTun;
TunInterface NetdBinderTest::sTun2;
TunInterface NetdBinderTest::sTun3;
+TunInterface NetdBinderTest::sTun4;
class TimedOperation : public Stopwatch {
public:
@@ -551,14 +565,22 @@ TEST_F(NetdBinderTest, BandwidthEnableDataSaver) {
}
static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
- const std::string& action, const char* ipVersion) {
+ const std::string& action, const char* ipVersion,
+ const char* oif) {
// Output looks like this:
+ // "<priority>:\tfrom all iif lo oif netdc0ca6 uidrange 500000-500000 lookup netdc0ca6"
// "<priority>:\tfrom all fwmark 0x0/0x20000 iif lo uidrange 1000-2000 prohibit"
std::vector<std::string> rules = listIpRules(ipVersion);
std::string prefix = StringPrintf("%" PRIu32 ":", priority);
- std::string suffix =
- StringPrintf(" iif lo uidrange %d-%d %s\n", range.start, range.stop, action.c_str());
+ std::string suffix;
+ if (oif) {
+ suffix = StringPrintf(" iif lo oif %s uidrange %d-%d %s\n", oif, range.start, range.stop,
+ action.c_str());
+ } else {
+ suffix = StringPrintf(" iif lo uidrange %d-%d %s\n", range.start, range.stop,
+ action.c_str());
+ }
for (const auto& line : rules) {
if (android::base::StartsWith(line, prefix) && android::base::EndsWith(line, suffix)) {
return true;
@@ -567,14 +589,20 @@ static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel&
return false;
}
+// Overloads function with oif parameter for VPN rules compare.
static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
- const std::string& action) {
- bool existsIp4 = ipRuleExistsForRange(priority, range, action, IP_RULE_V4);
- bool existsIp6 = ipRuleExistsForRange(priority, range, action, IP_RULE_V6);
+ const std::string& action, const char* oif) {
+ bool existsIp4 = ipRuleExistsForRange(priority, range, action, IP_RULE_V4, oif);
+ bool existsIp6 = ipRuleExistsForRange(priority, range, action, IP_RULE_V6, oif);
EXPECT_EQ(existsIp4, existsIp6);
return existsIp4;
}
+static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
+ const std::string& action) {
+ return ipRuleExistsForRange(priority, range, action, nullptr);
+}
+
namespace {
UidRangeParcel makeUidRangeParcel(int start, int stop) {
@@ -585,6 +613,17 @@ UidRangeParcel makeUidRangeParcel(int start, int stop) {
return res;
}
+NativeUidRangeConfig makeNativeUidRangeConfig(unsigned netId,
+ std::vector<UidRangeParcel>&& uidRanges,
+ uint32_t subPriority) {
+ NativeUidRangeConfig res;
+ res.netId = netId;
+ res.uidRanges = uidRanges;
+ res.subPriority = subPriority;
+
+ return res;
+}
+
} // namespace
TEST_F(NetdBinderTest, NetworkInterfaces) {
@@ -3948,32 +3987,69 @@ namespace {
#define VPN_NETID TEST_NETID3
void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRangeParcel>& uidRanges,
- const std::string& iface) {
+ const std::string& iface, uint32_t subPriority) {
ASSERT_EQ(expectedResults.size(), uidRanges.size());
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));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_NETWORK + subPriority,
+ 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));
+ ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_UID_IMPLICIT_NETWORK + subPriority,
+ uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_UNREACHABLE + subPriority,
+ uidRanges[i], action));
}
}
}
+void verifyAppUidRules(std::vector<bool>&& expectedResults, NativeUidRangeConfig& uidRangeConfig,
+ const std::string& iface) {
+ verifyAppUidRules(move(expectedResults), uidRangeConfig.uidRanges, iface,
+ uidRangeConfig.subPriority);
+}
+
+void verifyVpnUidRules(std::vector<bool>&& expectedResults, NativeUidRangeConfig& uidRangeConfig,
+ const std::string& iface, bool secure) {
+ ASSERT_EQ(expectedResults.size(), uidRangeConfig.uidRanges.size());
+ std::string action = StringPrintf("lookup %s ", iface.c_str());
+
+ uint32_t priority;
+ if (secure) {
+ priority = RULE_PRIORITY_SECURE_VPN;
+ } else {
+ priority = RULE_PRIORITY_BYPASSABLE_VPN;
+ }
+ for (unsigned long i = 0; i < uidRangeConfig.uidRanges.size(); i++) {
+ EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(priority + uidRangeConfig.subPriority,
+ uidRangeConfig.uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_EXPLICIT_NETWORK + uidRangeConfig.subPriority,
+ uidRangeConfig.uidRanges[i], action));
+ EXPECT_EQ(expectedResults[i],
+ ipRuleExistsForRange(RULE_PRIORITY_OUTPUT_INTERFACE + uidRangeConfig.subPriority,
+ uidRangeConfig.uidRanges[i], action, iface.c_str()));
+ }
+}
+
+constexpr int SUB_PRIORITY_1 = UidRanges::DEFAULT_SUB_PRIORITY + 1;
+constexpr int SUB_PRIORITY_2 = UidRanges::DEFAULT_SUB_PRIORITY + 2;
+
constexpr int IMPLICITLY_SELECT = 0;
constexpr int EXPLICITLY_SELECT = 1;
constexpr int UNCONNECTED_SOCKET = 2;
@@ -4087,18 +4163,24 @@ TEST_F(NetdBinderTest, PerAppDefaultNetwork_VerifyIpRules) {
makeUidRangeParcel(BASE_UID + 8090, BASE_UID + 8099)};
EXPECT_TRUE(mNetd->networkAddUidRanges(APP_DEFAULT_NETID, uidRanges).isOk());
- verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, sTun.name());
+ verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, sTun.name(),
+ UidRanges::DEFAULT_SUB_PRIORITY);
EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(0)}).isOk());
- verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, sTun.name());
+ verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, sTun.name(),
+ UidRanges::DEFAULT_SUB_PRIORITY);
EXPECT_TRUE(mNetd->networkRemoveUidRanges(APP_DEFAULT_NETID, {uidRanges.at(1)}).isOk());
- verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, sTun.name());
+ verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, sTun.name(),
+ UidRanges::DEFAULT_SUB_PRIORITY);
EXPECT_TRUE(mNetd->networkAddUidRanges(INetd::UNREACHABLE_NET_ID, uidRanges).isOk());
- verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, "");
+ verifyAppUidRules({true, true} /*expectedResults*/, uidRanges, "",
+ UidRanges::DEFAULT_SUB_PRIORITY);
EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(0)}).isOk());
- verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, "");
+ verifyAppUidRules({false, true} /*expectedResults*/, uidRanges, "",
+ UidRanges::DEFAULT_SUB_PRIORITY);
EXPECT_TRUE(mNetd->networkRemoveUidRanges(INetd::UNREACHABLE_NET_ID, {uidRanges.at(1)}).isOk());
- verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, "");
+ verifyAppUidRules({false, false} /*expectedResults*/, uidRanges, "",
+ UidRanges::DEFAULT_SUB_PRIORITY);
}
// Verify whether packets go through the right network with and without per-app default network.
@@ -4420,3 +4502,211 @@ TEST_F(NetdBinderTest, NetworkCreate) {
wrongConfig.vpnType = static_cast<NativeVpnType>(-1);
EXPECT_EQ(EINVAL, mNetd->networkCreate(wrongConfig).serviceSpecificErrorCode());
}
+
+// Verifies valid and invalid inputs on networkAddUidRangesParcel method.
+TEST_F(NetdBinderTest, UidRangeSubPriority_ValidateInputs) {
+ createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_NETID, VPN_NETID,
+ /*isSecureVPN=*/true);
+ // Invalid priority -1 on a physical network.
+ NativeUidRangeConfig uidRangeConfig =
+ makeNativeUidRangeConfig(APP_DEFAULT_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)},
+ UidRanges::DEFAULT_SUB_PRIORITY - 1);
+ binder::Status status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+
+ // Invalid priority 1000 on a physical network.
+ uidRangeConfig.subPriority = UidRanges::LOWEST_SUB_PRIORITY + 1;
+ status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+
+ // Virtual networks support only default priority.
+ uidRangeConfig.netId = VPN_NETID;
+ uidRangeConfig.subPriority = SUB_PRIORITY_1;
+ status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+
+ // For a single network, identical UID ranges with different priorities are allowed.
+ uidRangeConfig.netId = APP_DEFAULT_NETID;
+ uidRangeConfig.subPriority = SUB_PRIORITY_1;
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig).isOk());
+ 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)};
+ status = mNetd->networkAddUidRangesParcel(uidRangeConfig);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(EINVAL, status.serviceSpecificErrorCode());
+}
+
+// Examines whether IP rules for app default network with subsidiary priorities are correctly added
+// and removed.
+TEST_F(NetdBinderTest, UidRangeSubPriority_VerifyPhysicalNwIpRules) {
+ createPhysicalNetwork(TEST_NETID1, sTun.name());
+ EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk());
+ createPhysicalNetwork(TEST_NETID2, sTun2.name());
+ EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "::/0", "").isOk());
+
+ // Adds priority 1 setting
+ NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
+ TEST_NETID1, {makeUidRangeParcel(BASE_UID, BASE_UID)}, SUB_PRIORITY_1);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
+ verifyAppUidRules({true}, uidRangeConfig1, sTun.name());
+ // Adds priority 2 setting
+ NativeUidRangeConfig uidRangeConfig2 = makeNativeUidRangeConfig(
+ TEST_NETID2, {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)}, SUB_PRIORITY_2);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
+ verifyAppUidRules({true}, uidRangeConfig2, sTun2.name());
+ // Adds another priority 2 setting
+ NativeUidRangeConfig uidRangeConfig3 = makeNativeUidRangeConfig(
+ INetd::UNREACHABLE_NET_ID, {makeUidRangeParcel(BASE_UID + 2, BASE_UID + 2)},
+ SUB_PRIORITY_2);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig3).isOk());
+ verifyAppUidRules({true}, uidRangeConfig3, "");
+
+ // Removes.
+ EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
+ verifyAppUidRules({false}, uidRangeConfig1, sTun.name());
+ verifyAppUidRules({true}, uidRangeConfig2, sTun2.name());
+ verifyAppUidRules({true}, uidRangeConfig3, "");
+ EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig2).isOk());
+ verifyAppUidRules({false}, uidRangeConfig1, sTun.name());
+ verifyAppUidRules({false}, uidRangeConfig2, sTun2.name());
+ verifyAppUidRules({true}, uidRangeConfig3, "");
+ EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig3).isOk());
+ verifyAppUidRules({false}, uidRangeConfig1, sTun.name());
+ verifyAppUidRules({false}, uidRangeConfig2, sTun2.name());
+ verifyAppUidRules({false}, uidRangeConfig3, "");
+}
+
+// Verify uid range rules on virtual network.
+TEST_P(VpnParameterizedTest, UidRangeSubPriority_VerifyVpnIpRules) {
+ const bool isSecureVPN = GetParam();
+ constexpr int VPN_NETID2 = TEST_NETID2;
+
+ // Create 2 VPNs, using sTun and sTun2.
+ auto config = makeNativeNetworkConfig(VPN_NETID, NativeNetworkType::VIRTUAL,
+ INetd::PERMISSION_NONE, isSecureVPN);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID, sTun.name()).isOk());
+
+ config = makeNativeNetworkConfig(VPN_NETID2, NativeNetworkType::VIRTUAL, INetd::PERMISSION_NONE,
+ isSecureVPN);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(VPN_NETID2, sTun2.name()).isOk());
+
+ // Assign uid ranges to different VPNs. Check if rules match.
+ NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
+ VPN_NETID, {makeUidRangeParcel(BASE_UID, BASE_UID)}, UidRanges::DEFAULT_SUB_PRIORITY);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
+ verifyVpnUidRules({true}, uidRangeConfig1, sTun.name(), isSecureVPN);
+
+ NativeUidRangeConfig uidRangeConfig2 =
+ makeNativeUidRangeConfig(VPN_NETID2, {makeUidRangeParcel(BASE_UID + 1, BASE_UID + 1)},
+ UidRanges::DEFAULT_SUB_PRIORITY);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
+ verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN);
+
+ // Remove uid configs one-by-one. Check if rules match.
+ EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
+ verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN);
+ verifyVpnUidRules({true}, uidRangeConfig2, sTun2.name(), isSecureVPN);
+ EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig2).isOk());
+ verifyVpnUidRules({false}, uidRangeConfig1, sTun.name(), isSecureVPN);
+ verifyVpnUidRules({false}, uidRangeConfig2, sTun2.name(), isSecureVPN);
+}
+
+// Verify if packets go through the right network when subsidiary priority and VPN works together.
+//
+// Test config:
+// +----------+------------------------+-------------------------------------------+
+// | Priority | UID | Assigned Network |
+// +----------+------------------------+-------------------------------------------+
+// | 0 | TEST_UID1 | VPN bypassable (VPN_NETID) |
+// +----------+------------------------+-------------------------------------------+
+// | 1 | TEST_UID1, TEST_UID2, | Physical Network 1 (APP_DEFAULT_1_NETID) |
+// | 1 | TEST_UID3 | Physical Network 2 (APP_DEFAULT_2_NETID) |
+// | 1 | TEST_UID5 | Unreachable Network (UNREACHABLE_NET_ID) |
+// +----------+------------------------+-------------------------------------------+
+// | 2 | TEST_UID3 | Physical Network 1 (APP_DEFAULT_1_NETID) |
+// | 2 | TEST_UID4, TEST_UID5 | Physical Network 2 (APP_DEFAULT_2_NETID) |
+// +----------+------------------------+-------------------------------------------+
+//
+// Expected results:
+// +-----------+------------------------+
+// | UID | Using Network |
+// +-----------+------------------------+
+// | TEST_UID1 | VPN |
+// | TEST_UID2 | Physical Network 1 |
+// | TEST_UID3 | Physical Network 2 |
+// | TEST_UID4 | Physical Network 2 |
+// | TEST_UID5 | Unreachable Network |
+// | TEST_UID6 | System Default Network |
+// +-----------+------------------------+
+//
+// SYSTEM_DEFAULT_NETID uses sTun.
+// APP_DEFAULT_1_NETID uses sTun2.
+// VPN_NETID uses sTun3.
+// APP_DEFAULT_2_NETID uses sTun4.
+//
+TEST_F(NetdBinderTest, UidRangeSubPriority_ImplicitlySelectNetwork) {
+ constexpr int APP_DEFAULT_1_NETID = TEST_NETID2;
+ constexpr int APP_DEFAULT_2_NETID = TEST_NETID4;
+
+ // Creates 4 networks.
+ createVpnAndOtherPhysicalNetwork(SYSTEM_DEFAULT_NETID, APP_DEFAULT_1_NETID, VPN_NETID,
+ /*isSecureVPN=*/false);
+ createPhysicalNetwork(APP_DEFAULT_2_NETID, sTun4.name());
+ EXPECT_TRUE(mNetd->networkAddRoute(APP_DEFAULT_2_NETID, sTun4.name(), "::/0", "").isOk());
+
+ // Adds VPN setting.
+ NativeUidRangeConfig uidRangeConfigVpn = makeNativeUidRangeConfig(
+ VPN_NETID, {makeUidRangeParcel(TEST_UID1, TEST_UID1)}, UidRanges::DEFAULT_SUB_PRIORITY);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfigVpn).isOk());
+
+ // Adds uidRangeConfig1 setting.
+ NativeUidRangeConfig uidRangeConfig1 = makeNativeUidRangeConfig(
+ APP_DEFAULT_1_NETID,
+ {makeUidRangeParcel(TEST_UID1, TEST_UID1), makeUidRangeParcel(TEST_UID2, TEST_UID2)},
+ SUB_PRIORITY_1);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
+ uidRangeConfig1.netId = APP_DEFAULT_2_NETID;
+ uidRangeConfig1.uidRanges = {makeUidRangeParcel(TEST_UID3, TEST_UID3)};
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
+ uidRangeConfig1.netId = INetd::UNREACHABLE_NET_ID;
+ uidRangeConfig1.uidRanges = {makeUidRangeParcel(TEST_UID5, TEST_UID5)};
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig1).isOk());
+
+ // Adds uidRangeConfig2 setting.
+ NativeUidRangeConfig uidRangeConfig2 = makeNativeUidRangeConfig(
+ APP_DEFAULT_1_NETID, {makeUidRangeParcel(TEST_UID3, TEST_UID3)}, SUB_PRIORITY_2);
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
+ uidRangeConfig2.netId = APP_DEFAULT_2_NETID;
+ uidRangeConfig2.uidRanges = {makeUidRangeParcel(TEST_UID4, TEST_UID4),
+ makeUidRangeParcel(TEST_UID5, TEST_UID5)};
+ EXPECT_TRUE(mNetd->networkAddUidRangesParcel(uidRangeConfig2).isOk());
+
+ int systemDefaultFd = sTun.getFdForTesting();
+ int appDefault_1_Fd = sTun2.getFdForTesting();
+ int vpnFd = sTun3.getFdForTesting();
+ int appDefault_2_Fd = sTun4.getFdForTesting();
+ // Verify routings.
+ expectPacketSentOnNetId(TEST_UID1, VPN_NETID, vpnFd, IMPLICITLY_SELECT);
+ expectPacketSentOnNetId(TEST_UID2, APP_DEFAULT_1_NETID, appDefault_1_Fd, IMPLICITLY_SELECT);
+ expectPacketSentOnNetId(TEST_UID3, APP_DEFAULT_2_NETID, appDefault_2_Fd, IMPLICITLY_SELECT);
+ expectPacketSentOnNetId(TEST_UID4, APP_DEFAULT_2_NETID, appDefault_2_Fd, IMPLICITLY_SELECT);
+ expectUnreachableError(TEST_UID5, INetd::UNREACHABLE_NET_ID, IMPLICITLY_SELECT);
+ expectPacketSentOnNetId(TEST_UID6, SYSTEM_DEFAULT_NETID, systemDefaultFd, IMPLICITLY_SELECT);
+
+ // Remove test rules from the unreachable network.
+ EXPECT_TRUE(mNetd->networkRemoveUidRangesParcel(uidRangeConfig1).isOk());
+} \ No newline at end of file