diff options
author | Chalard Jean <jchalard@google.com> | 2022-12-27 04:31:50 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-12-27 04:31:50 +0000 |
commit | 6bda9ee8b6ed74e3c98bd6dbe4a21a1b7fe723c6 (patch) | |
tree | 1937cc9c9d97aff5bd025f995d21a492070c0168 | |
parent | 3755dbfd1271224199b778783b7a81abab676b4e (diff) | |
parent | 5edbf57b32ccac606edc4ad61912906a5e2ead5e (diff) | |
download | netd-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.cpp | 27 | ||||
-rw-r--r-- | server/RouteController.cpp | 58 | ||||
-rw-r--r-- | server/RouteController.h | 15 | ||||
-rw-r--r-- | tests/binder_test.cpp | 77 |
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 +} |