summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChalard Jean <jchalard@google.com>2022-12-27 04:31:50 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-12-27 04:31:50 +0000
commit6bda9ee8b6ed74e3c98bd6dbe4a21a1b7fe723c6 (patch)
tree1937cc9c9d97aff5bd025f995d21a492070c0168
parent3755dbfd1271224199b778783b7a81abab676b4e (diff)
parent5edbf57b32ccac606edc4ad61912906a5e2ead5e (diff)
downloadnetd-6bda9ee8b6ed74e3c98bd6dbe4a21a1b7fe723c6.tar.gz
Add local rules for local networks am: e479f31b99 am: 5edbf57b32
Original change: https://android-review.googlesource.com/c/platform/system/netd/+/2336812 Change-Id: I3398d658b9fbd3c11c7d5b0a8527bfa412cdea09 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--server/PhysicalNetwork.cpp27
-rw-r--r--server/RouteController.cpp58
-rw-r--r--server/RouteController.h15
-rw-r--r--tests/binder_test.cpp77
4 files changed, 123 insertions, 54 deletions
diff --git a/server/PhysicalNetwork.cpp b/server/PhysicalNetwork.cpp
index 923412a8..161fa2a7 100644
--- a/server/PhysicalNetwork.cpp
+++ b/server/PhysicalNetwork.cpp
@@ -61,12 +61,7 @@ PhysicalNetwork::PhysicalNetwork(unsigned netId, PhysicalNetwork::Delegate* dele
mDelegate(delegate),
mPermission(PERMISSION_NONE),
mIsDefault(false),
- mIsLocalNetwork(local) {
- // TODO : remove this log, it's only present to avoid -Wunused-private-field from blocking
- // compilation
- ALOGI("Created physical network instance netId=%d local=%s", netId,
- mIsLocalNetwork ? "true" : "false");
-}
+ mIsLocalNetwork(local) {}
PhysicalNetwork::~PhysicalNetwork() {}
@@ -120,8 +115,8 @@ int PhysicalNetwork::setPermission(Permission permission) {
destroySocketsLackingPermission(permission);
for (const std::string& interface : mInterfaces) {
- if (int ret = RouteController::modifyPhysicalNetworkPermission(mNetId, interface.c_str(),
- mPermission, permission)) {
+ if (int ret = RouteController::modifyPhysicalNetworkPermission(
+ mNetId, interface.c_str(), mPermission, permission, mIsLocalNetwork)) {
ALOGE("failed to change permission on interface %s of netId %u from %x to %x",
interface.c_str(), mNetId, mPermission, permission);
return ret;
@@ -178,8 +173,8 @@ int PhysicalNetwork::addUsers(const UidRanges& uidRanges, int32_t subPriority) {
}
for (const std::string& interface : mInterfaces) {
- int ret = RouteController::addUsersToPhysicalNetwork(mNetId, interface.c_str(),
- {{subPriority, uidRanges}});
+ int ret = RouteController::addUsersToPhysicalNetwork(
+ mNetId, interface.c_str(), {{subPriority, uidRanges}}, mIsLocalNetwork);
if (ret) {
ALOGE("failed to add users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
@@ -193,8 +188,8 @@ int PhysicalNetwork::removeUsers(const UidRanges& uidRanges, int32_t subPriority
if (!isValidSubPriority(subPriority)) return -EINVAL;
for (const std::string& interface : mInterfaces) {
- int ret = RouteController::removeUsersFromPhysicalNetwork(mNetId, interface.c_str(),
- {{subPriority, uidRanges}});
+ int ret = RouteController::removeUsersFromPhysicalNetwork(
+ mNetId, interface.c_str(), {{subPriority, uidRanges}}, mIsLocalNetwork);
if (ret) {
ALOGE("failed to remove users on interface %s of netId %u", interface.c_str(), mNetId);
return ret;
@@ -208,8 +203,8 @@ int PhysicalNetwork::addInterface(const std::string& interface) {
if (hasInterface(interface)) {
return 0;
}
- if (int ret = RouteController::addInterfaceToPhysicalNetwork(mNetId, interface.c_str(),
- mPermission, mUidRangeMap)) {
+ if (int ret = RouteController::addInterfaceToPhysicalNetwork(
+ mNetId, interface.c_str(), mPermission, mUidRangeMap, mIsLocalNetwork)) {
ALOGE("failed to add interface %s to netId %u", interface.c_str(), mNetId);
return ret;
}
@@ -235,8 +230,8 @@ int PhysicalNetwork::removeInterface(const std::string& interface) {
// done last as further requests to the RouteController regarding this interface will fail
// 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, mUidRangeMap)) {
+ if (int ret = RouteController::removeInterfaceFromPhysicalNetwork(
+ mNetId, interface.c_str(), mPermission, mUidRangeMap, mIsLocalNetwork)) {
ALOGE("failed to remove interface %s from netId %u", interface.c_str(), mNetId);
return ret;
}
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index 86b23b6d..97ca84e9 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -595,6 +595,34 @@ int modifyIncomingPacketMark(unsigned netId, const char* interface, Permission p
mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd);
}
+// A rule to route traffic based on an local network.
+//
+// Supports apps that send traffic to local IPs without binding to a particular network.
+//
+[[nodiscard]] static int modifyLocalNetworkRule(uint32_t table, bool add) {
+ Fwmark fwmark;
+ Fwmark mask;
+
+ fwmark.explicitlySelected = false;
+ mask.explicitlySelected = true;
+
+ if (const int ret = modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_LOCAL_NETWORK,
+ table, fwmark.intValue, mask.intValue, IIF_NONE, OIF_NONE,
+ INVALID_UID, INVALID_UID)) {
+ return ret;
+ }
+
+ fwmark.explicitlySelected = true;
+ mask.explicitlySelected = true;
+
+ fwmark.netId = INetd::LOCAL_NET_ID;
+ mask.netId = FWMARK_NET_ID_MASK;
+
+ return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_EXPLICIT_NETWORK, table,
+ fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, INVALID_UID,
+ INVALID_UID);
+}
+
// A rule to route traffic based on a chosen outgoing interface.
//
// Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already knows
@@ -858,7 +886,7 @@ int RouteController::configureDummyNetwork() {
/* static */
int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface,
const UidRangeMap& uidRangeMap, Permission permission,
- bool add, bool modifyNonUidBasedRules) {
+ bool add, bool modifyNonUidBasedRules, bool local) {
uint32_t table = getRouteTableForInterface(interface, false /* local */);
if (table == RT_TABLE_UNSPEC) {
return -ESRCH;
@@ -904,6 +932,11 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface
UidRanges::SUB_PRIORITY_HIGHEST, add)) {
return ret;
}
+ if (local) {
+ if (const int ret = modifyLocalNetworkRule(table, add)) {
+ return ret;
+ }
+ }
if (int ret = modifyOutputInterfaceRules(interface, table, permission, INVALID_UID, INVALID_UID,
UidRanges::SUB_PRIORITY_HIGHEST, add)) {
return ret;
@@ -1302,9 +1335,9 @@ int RouteController::removeInterfaceFromLocalNetwork(unsigned netId, const char*
int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
Permission permission,
- const UidRangeMap& uidRangeMap) {
+ const UidRangeMap& uidRangeMap, bool local) {
if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_ADD,
- MODIFY_NON_UID_BASED_RULES)) {
+ MODIFY_NON_UID_BASED_RULES, local)) {
return ret;
}
@@ -1320,9 +1353,10 @@ int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* i
int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const char* interface,
Permission permission,
- const UidRangeMap& uidRangeMap) {
+ const UidRangeMap& uidRangeMap,
+ bool local) {
if (int ret = modifyPhysicalNetwork(netId, interface, uidRangeMap, permission, ACTION_DEL,
- MODIFY_NON_UID_BASED_RULES)) {
+ MODIFY_NON_UID_BASED_RULES, local)) {
return ret;
}
@@ -1366,17 +1400,17 @@ int RouteController::removeInterfaceFromVirtualNetwork(unsigned netId, const cha
int RouteController::modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
- Permission newPermission) {
+ Permission newPermission, bool local) {
// 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, emptyUidRangeMap, newPermission,
- ACTION_ADD, MODIFY_NON_UID_BASED_RULES)) {
+ ACTION_ADD, MODIFY_NON_UID_BASED_RULES, local)) {
return ret;
}
return modifyPhysicalNetwork(netId, interface, emptyUidRangeMap, oldPermission, ACTION_DEL,
- MODIFY_NON_UID_BASED_RULES);
+ MODIFY_NON_UID_BASED_RULES, local);
}
int RouteController::addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges) {
@@ -1500,15 +1534,15 @@ int RouteController::removeVirtualNetworkFallthrough(unsigned vpnNetId,
}
int RouteController::addUsersToPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap) {
+ const UidRangeMap& uidRangeMap, bool local) {
return modifyPhysicalNetwork(netId, interface, uidRangeMap, PERMISSION_NONE, ACTION_ADD,
- !MODIFY_NON_UID_BASED_RULES);
+ !MODIFY_NON_UID_BASED_RULES, local);
}
int RouteController::removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap) {
+ const UidRangeMap& uidRangeMap, bool local) {
return modifyPhysicalNetwork(netId, interface, uidRangeMap, PERMISSION_NONE, ACTION_DEL,
- !MODIFY_NON_UID_BASED_RULES);
+ !MODIFY_NON_UID_BASED_RULES, local);
}
int RouteController::addUsersToUnreachableNetwork(unsigned netId, const UidRangeMap& uidRangeMap) {
diff --git a/server/RouteController.h b/server/RouteController.h
index 0d4e2b96..a56d4e05 100644
--- a/server/RouteController.h
+++ b/server/RouteController.h
@@ -121,11 +121,13 @@ public:
[[nodiscard]] static int addInterfaceToPhysicalNetwork(unsigned netId, const char* interface,
Permission permission,
- const UidRangeMap& uidRangeMap);
+ const UidRangeMap& uidRangeMap,
+ bool local);
[[nodiscard]] static int removeInterfaceFromPhysicalNetwork(unsigned netId,
const char* interface,
Permission permission,
- const UidRangeMap& uidRangeMap);
+ const UidRangeMap& uidRangeMap,
+ bool local);
[[nodiscard]] static int addInterfaceToVirtualNetwork(unsigned netId, const char* interface,
bool secure,
@@ -138,7 +140,7 @@ public:
[[nodiscard]] static int modifyPhysicalNetworkPermission(unsigned netId, const char* interface,
Permission oldPermission,
- Permission newPermission);
+ Permission newPermission, bool local);
[[nodiscard]] static int addUsersToVirtualNetwork(unsigned netId, const char* interface,
bool secure, const UidRangeMap& uidRangeMap,
@@ -179,10 +181,11 @@ public:
Permission permission);
[[nodiscard]] static int addUsersToPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap);
+ const UidRangeMap& uidRangeMap, bool local);
[[nodiscard]] static int removeUsersFromPhysicalNetwork(unsigned netId, const char* interface,
- const UidRangeMap& uidRangeMap);
+ const UidRangeMap& uidRangeMap,
+ bool local);
[[nodiscard]] static int addUsersToUnreachableNetwork(unsigned netId,
const UidRangeMap& uidRangeMap);
@@ -221,7 +224,7 @@ public:
static int modifyDefaultNetwork(uint16_t action, const char* interface, Permission permission);
static int modifyPhysicalNetwork(unsigned netId, const char* interface,
const UidRangeMap& uidRangeMap, Permission permission,
- bool add, bool modifyNonUidBasedRules);
+ bool add, bool modifyNonUidBasedRules, bool local);
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,
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index d4902bc8..135c13c7 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -121,6 +121,7 @@ using android::net::RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION;
using android::net::RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION;
using android::net::RULE_PRIORITY_DEFAULT_NETWORK;
using android::net::RULE_PRIORITY_EXPLICIT_NETWORK;
+using android::net::RULE_PRIORITY_LOCAL_NETWORK;
using android::net::RULE_PRIORITY_LOCAL_ROUTES;
using android::net::RULE_PRIORITY_OUTPUT_INTERFACE;
using android::net::RULE_PRIORITY_PROHIBIT_NON_VPN;
@@ -178,6 +179,8 @@ static const in6_addr V6_ADDR = {
{// 2001:db8:cafe::8888
.u6_addr8 = {0x20, 0x01, 0x0d, 0xb8, 0xca, 0xfe, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88}}};
+typedef enum { ALL_EXIST, NONE_EXIST } ExistMode;
+
class NetdBinderTest : public NetNativeTestBase {
public:
NetdBinderTest() {
@@ -734,6 +737,16 @@ TEST_F(NetdBinderTest, BandwidthEnableDataSaver) {
}
}
+static bool ipRuleExists(const char* ipVersion, const std::string& ipRule) {
+ std::vector<std::string> rules = listIpRules(ipVersion);
+ for (const auto& rule : rules) {
+ if (rule.find(ipRule) != std::string::npos) {
+ return true;
+ }
+ }
+ return false;
+}
+
static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel& range,
const std::string& action, const char* ipVersion,
const char* oif) {
@@ -773,6 +786,26 @@ static bool ipRuleExistsForRange(const uint32_t priority, const UidRangeParcel&
return ipRuleExistsForRange(priority, range, action, nullptr);
}
+static void expectRuleForV4AndV6(ExistMode mode, const std::string& rule) {
+ for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
+ if (mode == ALL_EXIST) {
+ EXPECT_TRUE(ipRuleExists(ipVersion, rule));
+ } else {
+ EXPECT_FALSE(ipRuleExists(ipVersion, rule));
+ }
+ }
+}
+
+static void expectLocalIpRuleExists(ExistMode mode, const std::string& ifName) {
+ std::string localIpRule = StringPrintf("%u:\tfrom all fwmark 0x0/0x10000 lookup %s",
+ RULE_PRIORITY_LOCAL_NETWORK, ifName.c_str());
+ expectRuleForV4AndV6(mode, localIpRule);
+
+ std::string dnsMasqRule = StringPrintf("%u:\tfrom all fwmark 0x10063/0x1ffff iif lo lookup %s",
+ RULE_PRIORITY_EXPLICIT_NETWORK, ifName.c_str());
+ expectRuleForV4AndV6(mode, dnsMasqRule);
+}
+
namespace {
UidRangeParcel makeUidRangeParcel(int start, int stop) {
@@ -849,6 +882,26 @@ TEST_F(NetdBinderTest, NetworkUidRules) {
EXPECT_EQ(ENONET, mNetd->networkDestroy(TEST_NETID1).serviceSpecificErrorCode());
}
+class LocalNetworkParameterizedTest : public NetdBinderTest,
+ public testing::WithParamInterface<bool> {};
+
+// Exercise both local and non-local networks
+INSTANTIATE_TEST_SUITE_P(LocalNetworkTests, LocalNetworkParameterizedTest, testing::Bool(),
+ [](const testing::TestParamInfo<bool>& info) {
+ return info.param ? "Local" : "NonLocal";
+ });
+
+TEST_P(LocalNetworkParameterizedTest, LocalNetworkUidRules) {
+ const bool local = GetParam();
+ const auto type = local ? NativeNetworkType::PHYSICAL_LOCAL : NativeNetworkType::PHYSICAL;
+ auto config = makeNativeNetworkConfig(TEST_NETID1, type, INetd::PERMISSION_NONE,
+ false /* secure */, false /* excludeLocalRoutes */);
+ EXPECT_TRUE(mNetd->networkCreate(config).isOk());
+ EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk());
+
+ expectLocalIpRuleExists(local ? ALL_EXIST : NONE_EXIST, sTun.name());
+}
+
TEST_F(NetdBinderTest, NetworkRejectNonSecureVpn) {
std::vector<UidRangeParcel> uidRanges = {makeUidRangeParcel(BASE_UID + 150, BASE_UID + 224),
makeUidRangeParcel(BASE_UID + 226, BASE_UID + 300)};
@@ -1566,16 +1619,6 @@ void expectStrictSetUidReject(const int uid) {
}
}
-bool ipRuleExists(const char* ipVersion, const std::string& ipRule) {
- std::vector<std::string> rules = listIpRules(ipVersion);
- for (const auto& rule : rules) {
- if (rule.find(ipRule) != std::string::npos) {
- return true;
- }
- }
- return false;
-}
-
std::vector<std::string> ipRouteSubstrings(const std::string& ifName, const std::string& dst,
const std::string& nextHop, const std::string& mtu) {
std::vector<std::string> routeSubstrings;
@@ -1637,18 +1680,14 @@ void expectNetworkDefaultIpRuleExists(const char* ifName) {
StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo lookup %s",
RULE_PRIORITY_DEFAULT_NETWORK, ifName);
- for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
- EXPECT_TRUE(ipRuleExists(ipVersion, networkDefaultRule));
- }
+ expectRuleForV4AndV6(ALL_EXIST, networkDefaultRule);
}
void expectNetworkDefaultIpRuleDoesNotExist() {
std::string networkDefaultRule =
StringPrintf("%u:\tfrom all fwmark 0x0/0xffff iif lo", RULE_PRIORITY_DEFAULT_NETWORK);
- for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
- EXPECT_FALSE(ipRuleExists(ipVersion, networkDefaultRule));
- }
+ expectRuleForV4AndV6(NONE_EXIST, networkDefaultRule);
}
void expectNetworkPermissionIpRuleExists(const char* ifName, int permission) {
@@ -1671,9 +1710,7 @@ void expectNetworkPermissionIpRuleExists(const char* ifName, int permission) {
break;
}
- for (const auto& ipVersion : {IP_RULE_V4, IP_RULE_V6}) {
- EXPECT_TRUE(ipRuleExists(ipVersion, networkPermissionRule));
- }
+ expectRuleForV4AndV6(ALL_EXIST, networkPermissionRule);
}
// TODO: It is a duplicate function, need to remove it
@@ -5516,4 +5553,4 @@ TEST_F(NetdBinderTest, PerProfileNetworkPermission) {
EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_2));
EXPECT_EQ(0, setNetworkForProcess(ENTERPRISE_NETID_3));
}
-} \ No newline at end of file
+}