summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-09 07:24:11 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-09 07:24:11 +0000
commitb2e0f9696b274895cc0720800a94f0d49f567dd9 (patch)
tree848e384ec4bf8096c7b8b8cdf71214a53bfe3c39
parent85c95a01a7ad7d60bb7fd95622b8f8d213e43b33 (diff)
parent5caee32dfdd6c91490f58f7b1f3b6e759b006880 (diff)
downloadnetd-b2e0f9696b274895cc0720800a94f0d49f567dd9.tar.gz
Snap for 8701348 from 5caee32dfdd6c91490f58f7b1f3b6e759b006880 to mainline-ipsec-release
Change-Id: I8abb8c0140def065d8f8dc87d0f118c3c29ac994
-rw-r--r--server/MDnsEventReporter.cpp52
-rw-r--r--server/MDnsEventReporter.h21
-rw-r--r--server/MDnsSdListener.cpp8
-rw-r--r--server/RouteController.cpp127
-rw-r--r--server/RouteController.h27
-rw-r--r--tests/binder_test.cpp171
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";