diff options
Diffstat (limited to 'tests/binder_test.cpp')
-rw-r--r-- | tests/binder_test.cpp | 122 |
1 files changed, 115 insertions, 7 deletions
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp index 5f5dff11..2133e1da 100644 --- a/tests/binder_test.cpp +++ b/tests/binder_test.cpp @@ -1627,6 +1627,90 @@ void expectProcessDoesNotExist(const std::string& processName) { } // namespace +TEST_F(NetdBinderTest, NetworkAddRemoveRouteToLocalExcludeTable) { + static const struct { + const char* ipVersion; + const char* testDest; + const char* testNextHop; + const bool expectInLocalTable; + } kTestData[] = { + {IP_RULE_V6, "::/0", "fe80::", false}, + {IP_RULE_V6, "::/0", "", false}, + {IP_RULE_V6, "2001:db8:cafe::/64", "fe80::", false}, + {IP_RULE_V6, "fe80::/64", "", true}, + {IP_RULE_V6, "2001:db8:cafe::/48", "", true}, + {IP_RULE_V6, "2001:db8:cafe::/64", "unreachable", false}, + {IP_RULE_V6, "2001:db8:ca00::/40", "", true}, + }; + + static const struct { + const char* ipVersion; + const char* testDest; + const char* testNextHop; + } kLinkLocalRoutes[] = {{IP_RULE_V6, "2001:db8::/32", ""}}; + + // Add test physical network + const auto& config = makeNativeNetworkConfig(TEST_NETID1, NativeNetworkType::PHYSICAL, + INetd::PERMISSION_NONE, false, false); + EXPECT_TRUE(mNetd->networkCreate(config).isOk()); + EXPECT_TRUE(mNetd->networkAddInterface(TEST_NETID1, sTun.name()).isOk()); + + // Get current default network NetId + binder::Status status = mNetd->networkGetDefault(&mStoredDefaultNetwork); + ASSERT_TRUE(status.isOk()) << status.exceptionMessage(); + + // Set default network + EXPECT_TRUE(mNetd->networkSetDefault(TEST_NETID1).isOk()); + + std::string localTableName = std::string(sTun.name() + "_local"); + // Set up link-local routes for connectivity to the "gateway" + for (size_t i = 0; i < std::size(kLinkLocalRoutes); i++) { + const auto& td = kLinkLocalRoutes[i]; + + binder::Status status = + mNetd->networkAddRoute(TEST_NETID1, sTun.name(), td.testDest, td.testNextHop); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectNetworkRouteExists(td.ipVersion, sTun.name(), td.testDest, td.testNextHop, + sTun.name().c_str()); + // Verify routes in local table + expectNetworkRouteExists(td.ipVersion, sTun.name(), td.testDest, td.testNextHop, + localTableName.c_str()); + } + + for (size_t i = 0; i < std::size(kTestData); i++) { + const auto& td = kTestData[i]; + + binder::Status status = + mNetd->networkAddRoute(TEST_NETID1, sTun.name(), td.testDest, td.testNextHop); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + // Verify routes in local table + if (td.expectInLocalTable) { + expectNetworkRouteExists(td.ipVersion, sTun.name(), td.testDest, td.testNextHop, + localTableName.c_str()); + } else { + expectNetworkRouteDoesNotExist(td.ipVersion, sTun.name(), td.testDest, td.testNextHop, + localTableName.c_str()); + } + + status = mNetd->networkRemoveRoute(TEST_NETID1, sTun.name(), td.testDest, td.testNextHop); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + expectNetworkRouteDoesNotExist(td.ipVersion, sTun.name(), td.testDest, td.testNextHop, + localTableName.c_str()); + } + + for (size_t i = 0; i < std::size(kLinkLocalRoutes); i++) { + const auto& td = kLinkLocalRoutes[i]; + status = mNetd->networkRemoveRoute(TEST_NETID1, sTun.name(), td.testDest, td.testNextHop); + EXPECT_TRUE(status.isOk()) << status.exceptionMessage(); + } + + // Set default network back + status = mNetd->networkSetDefault(mStoredDefaultNetwork); + + // Remove test physical network + EXPECT_TRUE(mNetd->networkDestroy(TEST_NETID1).isOk()); +} + namespace { bool getIpfwdV4Enable() { @@ -3309,6 +3393,9 @@ void NetdBinderTest::createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetI EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID1, sTun.name(), "::/0", "").isOk()); // Add limited route EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID2, sTun2.name(), "2001:db8::/32", "").isOk()); + + // Also add default route to non-default network for per app default use. + EXPECT_TRUE(mNetd->networkAddRoute(TEST_NETID3, sTun3.name(), "::/0", "").isOk()); } void NetdBinderTest::createAndSetDefaultNetwork(int netId, const std::string& interface, @@ -3473,10 +3560,10 @@ void expectVpnFallthroughRuleExists(const std::string& ifName, int vpnNetId) { } void expectVpnFallthroughWorks(android::net::INetd* netdService, bool bypassable, uid_t uid, - const TunInterface& fallthroughNetwork, - const TunInterface& vpnNetwork, - const TunInterface& nonDefaultNetwork, int vpnNetId = TEST_NETID2, - int fallthroughNetId = TEST_NETID1) { + uid_t uidNotInVpn, const TunInterface& fallthroughNetwork, + const TunInterface& vpnNetwork, const TunInterface& otherNetwork, + int vpnNetId = TEST_NETID2, int fallthroughNetId = TEST_NETID1, + int otherNetId = TEST_NETID3) { // Set default network to NETID_UNSET EXPECT_TRUE(netdService->networkSetDefault(NETID_UNSET).isOk()); @@ -3513,7 +3600,7 @@ void expectVpnFallthroughWorks(android::net::INetd* netdService, bool bypassable // Check if local exclusion rule exists for default network expectVpnLocalExclusionRuleExists(fallthroughNetwork.name(), true); // No local exclusion rule for non-default network - expectVpnLocalExclusionRuleExists(nonDefaultNetwork.name(), false); + expectVpnLocalExclusionRuleExists(otherNetwork.name(), false); // Expect fallthrough to default network // The fwmark differs depending on whether the VPN is bypassable or not. @@ -3553,6 +3640,25 @@ void expectVpnFallthroughWorks(android::net::INetd* netdService, bool bypassable EXPECT_FALSE(sendIPv6PacketFromUid(uid, outsideVpnAddr, &fwmark, fallthroughFd)); EXPECT_FALSE(sendIPv6PacketFromUid(uid, insideVpnAddr, &fwmark, fallthroughFd)); } + + // Add per-app uid ranges. + EXPECT_TRUE(netdService + ->networkAddUidRanges(otherNetId, + {makeUidRangeParcel(uidNotInVpn, uidNotInVpn)}) + .isOk()); + + int appDefaultFd = otherNetwork.getFdForTesting(); + + // UID is not inside the VPN range, so it won't go to vpn network. + // It won't fall into per app local rule because it's explicitly selected. + EXPECT_TRUE(sendIPv6PacketFromUid(uidNotInVpn, outsideVpnAddr, &fwmark, fallthroughFd)); + EXPECT_TRUE(sendIPv6PacketFromUid(uidNotInVpn, insideVpnAddr, &fwmark, fallthroughFd)); + + // Reset explicitly selection. + setNetworkForProcess(NETID_UNSET); + // Connections can go to app default network. + EXPECT_TRUE(sendIPv6PacketFromUid(uidNotInVpn, insideVpnAddr, &fwmark, appDefaultFd)); + EXPECT_TRUE(sendIPv6PacketFromUid(uidNotInVpn, outsideVpnAddr, &fwmark, appDefaultFd)); } } // namespace @@ -3561,14 +3667,16 @@ TEST_F(NetdBinderTest, SecureVPNFallthrough) { createVpnNetworkWithUid(true /* secure */, TEST_UID1); // Get current default network NetId ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk()); - expectVpnFallthroughWorks(mNetd.get(), false /* bypassable */, TEST_UID1, sTun, sTun2, sTun3); + expectVpnFallthroughWorks(mNetd.get(), false /* bypassable */, TEST_UID1, TEST_UID2, sTun, + sTun2, sTun3); } TEST_F(NetdBinderTest, BypassableVPNFallthrough) { createVpnNetworkWithUid(false /* secure */, TEST_UID1); // Get current default network NetId ASSERT_TRUE(mNetd->networkGetDefault(&mStoredDefaultNetwork).isOk()); - expectVpnFallthroughWorks(mNetd.get(), true /* bypassable */, TEST_UID1, sTun, sTun2, sTun3); + expectVpnFallthroughWorks(mNetd.get(), true /* bypassable */, TEST_UID1, TEST_UID2, sTun, sTun2, + sTun3); } namespace { |