diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-09 07:24:11 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-09 07:24:11 +0000 |
commit | b2e0f9696b274895cc0720800a94f0d49f567dd9 (patch) | |
tree | 848e384ec4bf8096c7b8b8cdf71214a53bfe3c39 | |
parent | 85c95a01a7ad7d60bb7fd95622b8f8d213e43b33 (diff) | |
parent | 5caee32dfdd6c91490f58f7b1f3b6e759b006880 (diff) | |
download | netd-b2e0f9696b274895cc0720800a94f0d49f567dd9.tar.gz |
Snap for 8701348 from 5caee32dfdd6c91490f58f7b1f3b6e759b006880 to mainline-ipsec-release
Change-Id: I8abb8c0140def065d8f8dc87d0f118c3c29ac994
-rw-r--r-- | server/MDnsEventReporter.cpp | 52 | ||||
-rw-r--r-- | server/MDnsEventReporter.h | 21 | ||||
-rw-r--r-- | server/MDnsSdListener.cpp | 8 | ||||
-rw-r--r-- | server/RouteController.cpp | 127 | ||||
-rw-r--r-- | server/RouteController.h | 27 | ||||
-rw-r--r-- | tests/binder_test.cpp | 171 |
6 files changed, 333 insertions, 73 deletions
diff --git a/server/MDnsEventReporter.cpp b/server/MDnsEventReporter.cpp index db9021ae..e94de367 100644 --- a/server/MDnsEventReporter.cpp +++ b/server/MDnsEventReporter.cpp @@ -18,6 +18,8 @@ #include "MDnsEventReporter.h" +using android::IInterface; +using android::sp; using android::net::mdns::aidl::IMDnsEventListener; MDnsEventReporter& MDnsEventReporter::getInstance() { @@ -30,11 +32,11 @@ const MDnsEventReporter::EventListenerSet& MDnsEventReporter::getEventListeners( return getEventListenersImpl(); } -int MDnsEventReporter::addEventListener(const android::sp<IMDnsEventListener>& listener) { +int MDnsEventReporter::addEventListener(const sp<IMDnsEventListener>& listener) { return addEventListenerImpl(listener); } -int MDnsEventReporter::removeEventListener(const android::sp<IMDnsEventListener>& listener) { +int MDnsEventReporter::removeEventListener(const sp<IMDnsEventListener>& listener) { return removeEventListenerImpl(listener); } @@ -43,7 +45,7 @@ const MDnsEventReporter::EventListenerSet& MDnsEventReporter::getEventListenersI return mEventListeners; } -int MDnsEventReporter::addEventListenerImpl(const android::sp<IMDnsEventListener>& listener) { +int MDnsEventReporter::addEventListenerImpl(const sp<IMDnsEventListener>& listener) { if (listener == nullptr) { ALOGE("The event listener should not be null"); return -EINVAL; @@ -52,39 +54,19 @@ int MDnsEventReporter::addEventListenerImpl(const android::sp<IMDnsEventListener std::lock_guard lock(mMutex); for (const auto& it : mEventListeners) { - if (android::IInterface::asBinder(it).get() == - android::IInterface::asBinder(listener).get()) { + if (IInterface::asBinder(it->getListener()).get() == IInterface::asBinder(listener).get()) { ALOGW("The event listener was already subscribed"); return -EEXIST; } } - // Create the death listener. - class DeathRecipient : public android::IBinder::DeathRecipient { - public: - DeathRecipient(MDnsEventReporter* eventReporter, - const android::sp<IMDnsEventListener>& listener) - : mEventReporter(eventReporter), mListener(listener) {} - ~DeathRecipient() override = default; - void binderDied(const android::wp<android::IBinder>& /* who */) override { - mEventReporter->removeEventListenerImpl(mListener); - } - - private: - MDnsEventReporter* mEventReporter; - android::sp<IMDnsEventListener> mListener; - }; - - android::sp<android::IBinder::DeathRecipient> deathRecipient = - new DeathRecipient(this, listener); - - android::IInterface::asBinder(listener)->linkToDeath(deathRecipient); - - mEventListeners.insert(listener); + auto eventListener = sp<EventListener>::make(this, listener); + IInterface::asBinder(listener)->linkToDeath(eventListener); + mEventListeners.insert(eventListener); return 0; } -int MDnsEventReporter::removeEventListenerImpl(const android::sp<IMDnsEventListener>& listener) { +int MDnsEventReporter::removeEventListenerImpl(const sp<IMDnsEventListener>& listener) { if (listener == nullptr) { ALOGE("The event listener should not be null"); return -EINVAL; @@ -92,6 +74,14 @@ int MDnsEventReporter::removeEventListenerImpl(const android::sp<IMDnsEventListe std::lock_guard lock(mMutex); - mEventListeners.erase(listener); - return 0; -} + for (const auto& it : mEventListeners) { + const auto& binder = IInterface::asBinder(it->getListener()); + if (binder == IInterface::asBinder(listener)) { + binder->unlinkToDeath(it); + mEventListeners.erase(it); + return 0; + } + } + ALOGE("The event listener does not exist"); + return -ENOENT; +}
\ No newline at end of file diff --git a/server/MDnsEventReporter.h b/server/MDnsEventReporter.h index e49c3e3f..cbc43ecb 100644 --- a/server/MDnsEventReporter.h +++ b/server/MDnsEventReporter.h @@ -23,10 +23,28 @@ class MDnsEventReporter final { public: + class EventListener : public android::IBinder::DeathRecipient { + public: + EventListener(MDnsEventReporter* eventReporter, + const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener) + : mEventReporter(eventReporter), mListener(listener) {} + ~EventListener() override = default; + void binderDied(const android::wp<android::IBinder>& /* who */) override { + mEventReporter->removeEventListenerImpl(mListener); + } + android::sp<android::net::mdns::aidl::IMDnsEventListener> getListener() { + return mListener; + } + + private: + MDnsEventReporter* mEventReporter; + android::sp<android::net::mdns::aidl::IMDnsEventListener> mListener; + }; + MDnsEventReporter(const MDnsEventReporter&) = delete; MDnsEventReporter& operator=(const MDnsEventReporter&) = delete; - using EventListenerSet = std::set<android::sp<android::net::mdns::aidl::IMDnsEventListener>>; + using EventListenerSet = std::set<android::sp<EventListener>>; // Get the instance of the singleton MDnsEventReporter. static MDnsEventReporter& getInstance(); @@ -56,5 +74,4 @@ class MDnsEventReporter final { const android::sp<android::net::mdns::aidl::IMDnsEventListener>& listener) EXCLUDES(mMutex); const EventListenerSet& getEventListenersImpl() const EXCLUDES(mMutex); - void handleEventBinderDied(const void* who) EXCLUDES(mMutex); }; diff --git a/server/MDnsSdListener.cpp b/server/MDnsSdListener.cpp index 16364008..1d1ea40a 100644 --- a/server/MDnsSdListener.cpp +++ b/server/MDnsSdListener.cpp @@ -140,7 +140,7 @@ void MDnsSdListenerDiscoverCallback(DNSServiceRef /* sdRef */, DNSServiceFlags f } for (const auto& it : listeners) { - it->onServiceDiscoveryStatus(info); + it->getListener()->onServiceDiscoveryStatus(info); } } @@ -212,7 +212,7 @@ void MDnsSdListenerRegisterCallback(DNSServiceRef /* sdRef */, DNSServiceFlags / } for (const auto& it : listeners) { - it->onServiceRegistrationStatus(info); + it->getListener()->onServiceRegistrationStatus(info); } } @@ -277,7 +277,7 @@ void MDnsSdListenerResolveCallback(DNSServiceRef /* sdRef */, DNSServiceFlags /* } for (const auto& it : listeners) { - it->onServiceResolutionStatus(info); + it->getListener()->onServiceResolutionStatus(info); } } @@ -343,7 +343,7 @@ void MDnsSdListenerGetAddrInfoCallback(DNSServiceRef /* sdRef */, DNSServiceFlag info.result = IMDnsEventListener::SERVICE_GET_ADDR_FAILED; } for (const auto& it : listeners) { - it->onGettingServiceAddressStatus(info); + it->getListener()->onGettingServiceAddressStatus(info); } } diff --git a/server/RouteController.cpp b/server/RouteController.cpp index 5ed33cdd..d2af9a37 100644 --- a/server/RouteController.cpp +++ b/server/RouteController.cpp @@ -21,9 +21,9 @@ #include <fcntl.h> #include <linux/fib_rules.h> #include <net/if.h> -#include <sys/stat.h> - +#include <netdutils/InternetAddresses.h> #include <private/android_filesystem_config.h> +#include <sys/stat.h> #include <map> @@ -43,6 +43,7 @@ using android::base::StartsWith; using android::base::StringPrintf; using android::base::WriteStringToFile; +using android::netdutils::IPPrefix; namespace android::net { @@ -63,6 +64,14 @@ const char* const ROUTE_TABLE_NAME_MAIN = "main"; const char* const RouteController::LOCAL_MANGLE_INPUT = "routectrl_mangle_INPUT"; +const IPPrefix V4_LOCAL_ADDR[] = { + IPPrefix::forString("169.254.0.0/16"), // Link Local + IPPrefix::forString("100.64.0.0/10"), // CGNAT + IPPrefix::forString("10.0.0.0/8"), // RFC1918 + IPPrefix::forString("172.16.0.0/12"), // RFC1918 + IPPrefix::forString("192.168.0.0/16") // RFC1918 +}; + const uint8_t AF_FAMILIES[] = {AF_INET, AF_INET6}; const uid_t UID_ROOT = 0; @@ -859,6 +868,13 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface subPriority, add)) { return ret; } + + // Per-UID local network rules must always match per-app default network rules, + // because their purpose is to allow the UIDs to use the default network for + // local destinations within it. + if (int ret = modifyUidLocalNetworkRule(interface, range.start, range.stop, add)) { + return ret; + } } } } @@ -906,6 +922,32 @@ int RouteController::modifyPhysicalNetwork(unsigned netId, const char* interface return 0; } +int RouteController::modifyUidLocalNetworkRule(const char* interface, uid_t uidStart, uid_t uidEnd, + bool add) { + uint32_t table = getRouteTableForInterface(interface, true /* local */); + if (table == RT_TABLE_UNSPEC) { + return -ESRCH; + } + + if ((uidStart == INVALID_UID) || (uidEnd == INVALID_UID)) { + ALOGE("modifyUidLocalNetworkRule, invalid UIDs (%u, %u)", uidStart, uidEnd); + return -EUSERS; + } + + Fwmark fwmark; + Fwmark mask; + + fwmark.explicitlySelected = false; + mask.explicitlySelected = true; + + // Access to this network is controlled by UID rules, not permission bits. + fwmark.permission = PERMISSION_NONE; + mask.permission = PERMISSION_NONE; + + return modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE, RULE_PRIORITY_UID_LOCAL_ROUTES, table, + fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE, uidStart, uidEnd); +} + [[nodiscard]] static int modifyUidUnreachableRule(unsigned netId, uid_t uidStart, uid_t uidEnd, int32_t subPriority, bool add, bool explicitSelect) { @@ -1074,11 +1116,11 @@ int RouteController::modifyTetheredNetwork(uint16_t action, const char* inputInt // Returns 0 on success or negative errno on failure. int RouteController::modifyRoute(uint16_t action, uint16_t flags, const char* interface, const char* destination, const char* nexthop, TableType tableType, - int mtu, int priority) { + int mtu, int priority, bool isLocal) { uint32_t table; switch (tableType) { case RouteController::INTERFACE: { - table = getRouteTableForInterface(interface, false /* local */); + table = getRouteTableForInterface(interface, isLocal); if (table == RT_TABLE_UNSPEC) { return -ESRCH; } @@ -1252,10 +1294,6 @@ int RouteController::addInterfaceToPhysicalNetwork(unsigned netId, const char* i MODIFY_NON_UID_BASED_RULES)) { return ret; } - // TODO: Consider to remove regular table if adding local table failed. - if (int ret = modifyVpnLocalExclusionRule(true, interface)) { - return ret; - } maybeModifyQdiscClsact(interface, ACTION_ADD); updateTableNamesFile(); @@ -1270,10 +1308,7 @@ int RouteController::removeInterfaceFromPhysicalNetwork(unsigned netId, const ch return ret; } - int ret = modifyVpnLocalExclusionRule(false, interface); - // Always perform flushRoute even if removing local exclusion rules failed. - ret |= flushRoutes(interface); - if (ret) { + if (int ret = flushRoutes(interface)) { return ret; } @@ -1357,22 +1392,66 @@ int RouteController::removeInterfaceFromDefaultNetwork(const char* interface, return modifyDefaultNetwork(RTM_DELRULE, interface, permission); } +bool RouteController::isTargetV4LocalRange(const char* dst) { + for (IPPrefix addr : V4_LOCAL_ADDR) { + if (addr.contains(IPPrefix::forString(dst))) { + return true; + } + } + return false; +} + +bool RouteController::isLocalAddress(TableType tableType, const char* destination, + const char* nexthop) { + IPPrefix prefix = IPPrefix::forString(destination); + return nexthop == nullptr && tableType == RouteController::INTERFACE && + // Skip default route to prevent network being modeled as point-to-point interfaces. + ((prefix.family() == AF_INET6 && prefix != IPPrefix::forString("::/0")) || + // Skip adding non-target local network range. + (prefix.family() == AF_INET && isTargetV4LocalRange(destination))); +} + int RouteController::addRoute(const char* interface, const char* destination, const char* nexthop, TableType tableType, int mtu, int priority) { - return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination, nexthop, - tableType, mtu, priority); + if (int ret = modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination, + nexthop, tableType, mtu, priority, false /* isLocal */)) { + return ret; + } + + if (isLocalAddress(tableType, destination, nexthop)) { + return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination, + nexthop, tableType, mtu, priority, true /* isLocal */); + } + + return 0; } int RouteController::removeRoute(const char* interface, const char* destination, const char* nexthop, TableType tableType, int priority) { - return modifyRoute(RTM_DELROUTE, NETLINK_REQUEST_FLAGS, interface, destination, nexthop, - tableType, 0 /* mtu */, priority); + if (int ret = modifyRoute(RTM_DELROUTE, NETLINK_REQUEST_FLAGS, interface, destination, nexthop, + tableType, 0 /* mtu */, priority, false /* isLocal */)) { + return ret; + } + + if (isLocalAddress(tableType, destination, nexthop)) { + return modifyRoute(RTM_DELROUTE, NETLINK_REQUEST_FLAGS, interface, destination, nexthop, + tableType, 0 /* mtu */, priority, true /* isLocal */); + } + return 0; } int RouteController::updateRoute(const char* interface, const char* destination, const char* nexthop, TableType tableType, int mtu) { - return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_REPLACE_FLAGS, interface, destination, nexthop, - tableType, mtu, 0 /* priority */); + if (int ret = modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_REPLACE_FLAGS, interface, destination, + nexthop, tableType, mtu, 0 /* priority */, false /* isLocal */)) { + return ret; + } + + if (isLocalAddress(tableType, destination, nexthop)) { + return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_REPLACE_FLAGS, interface, destination, + nexthop, tableType, mtu, 0 /* priority */, true /* isLocal */); + } + return 0; } int RouteController::enableTethering(const char* inputInterface, const char* outputInterface) { @@ -1385,13 +1464,21 @@ int RouteController::disableTethering(const char* inputInterface, const char* ou int RouteController::addVirtualNetworkFallthrough(unsigned vpnNetId, const char* physicalInterface, Permission permission) { - return modifyVpnFallthroughRule(RTM_NEWRULE, vpnNetId, physicalInterface, permission); + if (int ret = modifyVpnFallthroughRule(RTM_NEWRULE, vpnNetId, physicalInterface, permission)) { + return ret; + } + + return modifyVpnLocalExclusionRule(true /* add */, physicalInterface); } int RouteController::removeVirtualNetworkFallthrough(unsigned vpnNetId, const char* physicalInterface, Permission permission) { - return modifyVpnFallthroughRule(RTM_DELRULE, vpnNetId, physicalInterface, permission); + if (int ret = modifyVpnFallthroughRule(RTM_DELRULE, vpnNetId, physicalInterface, permission)) { + return ret; + } + + return modifyVpnLocalExclusionRule(false /* add */, physicalInterface); } int RouteController::addUsersToPhysicalNetwork(unsigned netId, const char* interface, diff --git a/server/RouteController.h b/server/RouteController.h index 9b04cfd2..ff41678d 100644 --- a/server/RouteController.h +++ b/server/RouteController.h @@ -55,11 +55,17 @@ constexpr int32_t RULE_PRIORITY_TETHERING = 21000; constexpr int32_t RULE_PRIORITY_UID_IMPLICIT_NETWORK = 22000; constexpr int32_t RULE_PRIORITY_IMPLICIT_NETWORK = 23000; constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_NO_LOCAL_EXCLUSION = 24000; -// Rules used for excluding local route in the VPN network. -constexpr int32_t RULE_PRIORITY_LOCAL_ROUTES = 25000; -constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION = 26000; -constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH = 27000; -constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 28000; +// Sets of rules used for excluding local routes from the VPN. Look up tables +// that contain directly-connected local routes taken from the default network. +// The first set is used for apps that have a per-UID default network. The rule +// UID ranges match those of the per-UID default network rule for that network. +// The second set has no UID ranges and is used for apps whose default network +// is the system default network network. +constexpr int32_t RULE_PRIORITY_UID_LOCAL_ROUTES = 25000; +constexpr int32_t RULE_PRIORITY_LOCAL_ROUTES = 26000; +constexpr int32_t RULE_PRIORITY_BYPASSABLE_VPN_LOCAL_EXCLUSION = 27000; +constexpr int32_t RULE_PRIORITY_VPN_FALLTHROUGH = 28000; +constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 29000; // Rule used when framework wants to disable default network from specified applications. There will // be a small interval the same uid range exists in both UID_DEFAULT_UNREACHABLE and // UID_DEFAULT_NETWORK when framework is switching user preferences. @@ -74,8 +80,8 @@ constexpr int32_t RULE_PRIORITY_UID_DEFAULT_NETWORK = 28000; // The priority is lower than UID_DEFAULT_NETWORK. Otherwise, the app will be told by // ConnectivityService that it has a network in step 1 of the second case. But if it tries to use // the network, it will not work. That will potentially cause a user-visible error. -constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 29000; -constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK = 30000; +constexpr int32_t RULE_PRIORITY_UID_DEFAULT_UNREACHABLE = 30000; +constexpr int32_t RULE_PRIORITY_DEFAULT_NETWORK = 31000; constexpr int32_t RULE_PRIORITY_UNREACHABLE = 32000; // clang-format on @@ -211,7 +217,7 @@ public: 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, int priority); + int mtu, int priority, bool isLocal); static int modifyTetheredNetwork(uint16_t action, const char* inputInterface, const char* outputInterface); static int modifyVpnFallthroughRule(uint16_t action, unsigned vpnNetId, @@ -221,6 +227,11 @@ public: bool modifyNonUidBasedRules, bool excludeLocalRoutes); static void updateTableNamesFile() EXCLUDES(sInterfaceToTableLock); static int modifyVpnLocalExclusionRule(bool add, const char* physicalInterface); + + static int modifyUidLocalNetworkRule(const char* interface, uid_t uidStart, uid_t uidEnd, + bool add); + static bool isLocalAddress(TableType tableType, const char* destination, const char* nexthop); + static bool isTargetV4LocalRange(const char* addrstr); }; // Public because they are called by by RouteControllerTest.cpp. diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp index 519effea..f423ea38 100644 --- a/tests/binder_test.cpp +++ b/tests/binder_test.cpp @@ -129,6 +129,7 @@ using android::net::RULE_PRIORITY_UID_DEFAULT_NETWORK; using android::net::RULE_PRIORITY_UID_DEFAULT_UNREACHABLE; using android::net::RULE_PRIORITY_UID_EXPLICIT_NETWORK; using android::net::RULE_PRIORITY_UID_IMPLICIT_NETWORK; +using android::net::RULE_PRIORITY_UID_LOCAL_ROUTES; using android::net::RULE_PRIORITY_VPN_FALLTHROUGH; using android::net::SockDiag; using android::net::TetherOffloadRuleParcel; @@ -225,7 +226,8 @@ class NetdBinderTest : public ::testing::Test { unique_fd* acceptedSocket); void createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetId = TEST_NETID2, - int fallthroughNetId = TEST_NETID1); + int fallthroughNetId = TEST_NETID1, + int nonDefaultNetId = TEST_NETID3); void createAndSetDefaultNetwork(int netId, const std::string& interface, int permission = INetd::PERMISSION_NONE); @@ -1625,6 +1627,121 @@ 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}, + {IP_RULE_V4, "0.0.0.0/0", "10.251.10.1", false}, + {IP_RULE_V4, "192.1.0.0/16", "", false}, + {IP_RULE_V4, "192.168.0.0/15", "", false}, + {IP_RULE_V4, "192.168.0.0/16", "", true}, + {IP_RULE_V4, "192.168.0.0/24", "", true}, + {IP_RULE_V4, "100.1.0.0/16", "", false}, + {IP_RULE_V4, "100.0.0.0/8", "", false}, + {IP_RULE_V4, "100.64.0.0/10", "", true}, + {IP_RULE_V4, "100.64.0.0/16", "", true}, + {IP_RULE_V4, "100.64.0.0/10", "throw", false}, + {IP_RULE_V4, "172.0.0.0/8", "", false}, + {IP_RULE_V4, "172.16.0.0/12", "", true}, + {IP_RULE_V4, "172.16.0.0/16", "", true}, + {IP_RULE_V4, "172.16.0.0/12", "unreachable", false}, + {IP_RULE_V4, "172.32.0.0/12", "", false}, + {IP_RULE_V4, "169.0.0.0/8", "", false}, + {IP_RULE_V4, "169.254.0.0/16", "", true}, + {IP_RULE_V4, "169.254.0.0/20", "", true}, + {IP_RULE_V4, "169.254.3.0/24", "", true}, + {IP_RULE_V4, "170.254.0.0/16", "", false}, + {IP_RULE_V4, "10.0.0.0/8", "", true}, + {IP_RULE_V4, "10.0.0.0/7", "", false}, + {IP_RULE_V4, "10.0.0.0/16", "", true}, + {IP_RULE_V4, "10.251.0.0/16", "", true}, + {IP_RULE_V4, "10.251.250.0/24", "", true}, + {IP_RULE_V4, "10.251.10.2/31", "throw", false}, + {IP_RULE_V4, "10.251.10.2/31", "unreachable", false}}; + + // To ensure that the nexthops for the above are reachable. + // Otherwise, the routes can't be created. + static const struct { + const char* ipVersion; + const char* testDest; + const char* testNextHop; + } kDirectlyConnectedRoutes[] = { + {IP_RULE_V4, "10.251.10.0/30", ""}, + {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(kDirectlyConnectedRoutes); i++) { + const auto& td = kDirectlyConnectedRoutes[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]; + SCOPED_TRACE(StringPrintf("case ip:%s, dest:%s, nexHop:%s, expect:%d", td.ipVersion, + td.testDest, td.testNextHop, td.expectInLocalTable)); + 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(kDirectlyConnectedRoutes); i++) { + const auto& td = kDirectlyConnectedRoutes[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() { @@ -3272,18 +3389,26 @@ TEST_F(NetdBinderTest, OemNetdRelated) { } void NetdBinderTest::createVpnNetworkWithUid(bool secure, uid_t uid, int vpnNetId, - int fallthroughNetId) { + int fallthroughNetId, int nonDefaultNetId) { // Re-init sTun* to ensure route rule exists. sTun.destroy(); sTun.init(); sTun2.destroy(); sTun2.init(); + sTun3.destroy(); + sTun3.init(); // Create physical network with fallthroughNetId but not set it as default network auto config = makeNativeNetworkConfig(fallthroughNetId, NativeNetworkType::PHYSICAL, INetd::PERMISSION_NONE, false, false); EXPECT_TRUE(mNetd->networkCreate(config).isOk()); EXPECT_TRUE(mNetd->networkAddInterface(fallthroughNetId, sTun.name()).isOk()); + // Create another physical network in order to test VPN behaviour with multiple networks + // connected, of which one may be the default. + auto nonDefaultNetworkConfig = makeNativeNetworkConfig( + nonDefaultNetId, NativeNetworkType::PHYSICAL, INetd::PERMISSION_NONE, false, false); + EXPECT_TRUE(mNetd->networkCreate(nonDefaultNetworkConfig).isOk()); + EXPECT_TRUE(mNetd->networkAddInterface(nonDefaultNetId, sTun3.name()).isOk()); // Create VPN with vpnNetId config.netId = vpnNetId; @@ -3299,6 +3424,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, @@ -3463,9 +3591,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, 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()); @@ -3499,8 +3628,10 @@ void expectVpnFallthroughWorks(android::net::INetd* netdService, bool bypassable // Check if fallthrough rule exists expectVpnFallthroughRuleExists(fallthroughNetwork.name(), vpnNetId); - // Check if local exclusion rule exists + // Check if local exclusion rule exists for default network expectVpnLocalExclusionRuleExists(fallthroughNetwork.name(), true); + // No local exclusion rule for non-default network + expectVpnLocalExclusionRuleExists(otherNetwork.name(), false); // Expect fallthrough to default network // The fwmark differs depending on whether the VPN is bypassable or not. @@ -3540,6 +3671,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 @@ -3548,14 +3698,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); + 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); + expectVpnFallthroughWorks(mNetd.get(), true /* bypassable */, TEST_UID1, TEST_UID2, sTun, sTun2, + sTun3); } namespace { @@ -4013,6 +4165,7 @@ void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRange ASSERT_EQ(expectedResults.size(), uidRanges.size()); if (iface.size()) { std::string action = StringPrintf("lookup %s ", iface.c_str()); + std::string action_local = StringPrintf("lookup %s_local ", iface.c_str()); for (unsigned long i = 0; i < uidRanges.size(); i++) { EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_EXPLICIT_NETWORK + subPriority, @@ -4023,6 +4176,8 @@ void verifyAppUidRules(std::vector<bool>&& expectedResults, std::vector<UidRange EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_DEFAULT_NETWORK + subPriority, uidRanges[i], action)); + EXPECT_EQ(expectedResults[i], ipRuleExistsForRange(RULE_PRIORITY_UID_LOCAL_ROUTES, + uidRanges[i], action_local)); } } else { std::string action = "unreachable"; |