NetworkController.cpp revision 738c93ee075354ffafb3a8ceef76e9aa711f057b
1a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak/*
2a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * Copyright (C) 2014 The Android Open Source Project
3a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *
4a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * Licensed under the Apache License, Version 2.0 (the "License");
5a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * you may not use this file except in compliance with the License.
6a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * You may obtain a copy of the License at
7a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *
8a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *      http://www.apache.org/licenses/LICENSE-2.0
9a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak *
10a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * Unless required by applicable law or agreed to in writing, software
11a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * distributed under the License is distributed on an "AS IS" BASIS,
12a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * See the License for the specific language governing permissions and
14a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak * limitations under the License.
15a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak */
16a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
1772604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// THREAD-SAFETY
1872604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// -------------
1972604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// The methods in this file are called from multiple threads (from CommandListener, FwmarkServer
2072604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// and DnsProxyListener). So, all accesses to shared state are guarded by a lock.
2172604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//
2272604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// In some cases, a single non-const method acquires and releases the lock several times, like so:
2372604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     if (isValidNetwork(...)) {  // isValidNetwork() acquires and releases the lock.
2472604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//        setDefaultNetwork(...);  // setDefaultNetwork() also acquires and releases the lock.
2572604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//
2672604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// It might seem that this allows races where the state changes between the two statements, but in
2772604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// fact there are no races because:
2872604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     1. This pattern only occurs in non-const methods (i.e., those that mutate state).
2972604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     2. Only CommandListener calls these non-const methods. The others call only const methods.
3072604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran//     3. CommandListener only processes one command at a time. I.e., it's serialized.
3172604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran// Thus, no other mutation can occur in between the two statements above.
32a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
33a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak#include "NetworkController.h"
34a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
351011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran#include "Fwmark.h"
366a773534e7f8541f221f27fb8063af079b1a5936Sreeram Ramachandran#include "LocalNetwork.h"
37f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran#include "PhysicalNetwork.h"
385c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include "RouteController.h"
394043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran#include "VirtualNetwork.h"
405c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
41ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran#include "cutils/misc.h"
42f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran#define LOG_TAG "Netd"
43f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran#include "log/log.h"
4472604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran#include "resolv_netid.h"
4572604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran
465c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandrannamespace {
475c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
485c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran// Keep these in sync with ConnectivityService.java.
49f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranconst unsigned MIN_NET_ID = 10;
50f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranconst unsigned MAX_NET_ID = 65535;
515c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
525c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran}  // namespace
535c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
5448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran// All calls to methods here are made while holding a write lock on mRWLock.
5548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranclass NetworkController::DelegateImpl : public PhysicalNetwork::Delegate {
5648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranpublic:
5748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    explicit DelegateImpl(NetworkController* networkController);
5848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    virtual ~DelegateImpl();
5948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
6048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int modifyFallthrough(unsigned vpnNetId, const std::string& physicalInterface,
6148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                          Permission permission, bool add) WARN_UNUSED_RESULT;
6248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
6348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranprivate:
6448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int addFallthrough(const std::string& physicalInterface,
6548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                       Permission permission) override WARN_UNUSED_RESULT;
6648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int removeFallthrough(const std::string& physicalInterface,
6748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                          Permission permission) override WARN_UNUSED_RESULT;
6848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
6948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    int modifyFallthrough(const std::string& physicalInterface, Permission permission,
7048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                          bool add) WARN_UNUSED_RESULT;
7148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
7248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    NetworkController* const mNetworkController;
7348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran};
7448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
7548e19b037e7e20674048ef76bf31ce65c741347cSreeram RamachandranNetworkController::DelegateImpl::DelegateImpl(NetworkController* networkController) :
7648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        mNetworkController(networkController) {
7748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
7848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
7948e19b037e7e20674048ef76bf31ce65c741347cSreeram RamachandranNetworkController::DelegateImpl::~DelegateImpl() {
8048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
8148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
8248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::modifyFallthrough(unsigned vpnNetId,
8348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       const std::string& physicalInterface,
8448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       Permission permission, bool add) {
8548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    if (add) {
8648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = RouteController::addVirtualNetworkFallthrough(vpnNetId,
8748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                    physicalInterface.c_str(),
8848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                    permission)) {
8948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            ALOGE("failed to add fallthrough to %s for VPN netId %u", physicalInterface.c_str(),
9048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                  vpnNetId);
9148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
9248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
9348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    } else {
9448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = RouteController::removeVirtualNetworkFallthrough(vpnNetId,
9548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                       physicalInterface.c_str(),
9648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                                       permission)) {
9748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            ALOGE("failed to remove fallthrough to %s for VPN netId %u", physicalInterface.c_str(),
9848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                  vpnNetId);
9948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
10048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
10148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
10248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return 0;
10348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
10448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
10548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::addFallthrough(const std::string& physicalInterface,
10648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                    Permission permission) {
10748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return modifyFallthrough(physicalInterface, permission, true);
10848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
10948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
11048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::removeFallthrough(const std::string& physicalInterface,
11148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       Permission permission) {
11248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return modifyFallthrough(physicalInterface, permission, false);
11348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
11448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
11548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::DelegateImpl::modifyFallthrough(const std::string& physicalInterface,
11648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       Permission permission, bool add) {
11748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    for (const auto& entry : mNetworkController->mNetworks) {
11848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (entry.second->getType() == Network::VIRTUAL) {
11948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            if (int ret = modifyFallthrough(entry.first, physicalInterface, permission, add)) {
12048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                return ret;
12148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            }
12248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
12348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
12448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return 0;
12548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
12648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
12748e19b037e7e20674048ef76bf31ce65c741347cSreeram RamachandranNetworkController::NetworkController() :
12848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        mDelegateImpl(new NetworkController::DelegateImpl(this)), mDefaultNetId(NETID_UNSET) {
12987475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran    mNetworks[LOCAL_NET_ID] = new LocalNetwork(LOCAL_NET_ID);
130a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
131a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
132a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczakunsigned NetworkController::getDefaultNetwork() const {
1339c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
134a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak    return mDefaultNetId;
135a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
136a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
137f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::setDefaultNetwork(unsigned netId) {
138f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
1399c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
140f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (netId == mDefaultNetId) {
141f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        return 0;
1429c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    }
1439c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
144f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (netId != NETID_UNSET) {
14536ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        Network* network = getNetworkLocked(netId);
146738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (!network) {
147738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("no such netId %u", netId);
148738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            return -ENONET;
149738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        }
150738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (network->getType() != Network::PHYSICAL) {
151738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("cannot set default to non-physical network with netId %u", netId);
152f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return -EINVAL;
153f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        }
15436ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->addAsDefault()) {
155f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
1569c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran        }
1579c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    }
1589c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
159f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (mDefaultNetId != NETID_UNSET) {
16036ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        Network* network = getNetworkLocked(mDefaultNetId);
16136ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (!network || network->getType() != Network::PHYSICAL) {
162f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
163f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return -ESRCH;
164f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        }
16536ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
166f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
1679c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran        }
1689c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran    }
1699c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran
170f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    mDefaultNetId = netId;
171f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return 0;
172a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
173a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
1741011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranuint32_t NetworkController::getNetworkForDns(unsigned* netId, uid_t uid) const {
1751011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
1761011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Fwmark fwmark;
1771011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    fwmark.protectedFromVpn = true;
1781011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    fwmark.permission = PERMISSION_SYSTEM;
1791011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (canUserSelectNetworkLocked(uid, *netId)) {
1801011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // If a non-zero NetId was explicitly specified, and the user has permission for that
1811011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // network, use that network's DNS servers. Do not fall through to the default network even
1821011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // if the explicitly selected network is a split tunnel VPN or a VPN without DNS servers.
1831011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        fwmark.explicitlySelected = true;
1841011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    } else {
1851011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // If the user is subject to a VPN and the VPN provides DNS servers, use those servers
1861011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // (possibly falling through to the default network if the VPN doesn't provide a route to
1871011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        // them). Otherwise, use the default network's DNS servers.
1881011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
1891011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        if (virtualNetwork && virtualNetwork->getHasDns()) {
1901011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran            *netId = virtualNetwork->getNetId();
1911011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        } else {
1921011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran            *netId = mDefaultNetId;
1931011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        }
1941011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
1951011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    fwmark.netId = *netId;
1961011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return fwmark.intValue;
1971011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran}
1981011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran
1991011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// Returns the NetId that a given UID would use if no network is explicitly selected. Specifically,
2001011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// the VPN that applies to the UID if any; otherwise, the default network.
2011011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranunsigned NetworkController::getNetworkForUser(uid_t uid) const {
2021011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
2031011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid)) {
2041011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        return virtualNetwork->getNetId();
2051011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
2061011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return mDefaultNetId;
2071011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran}
2081011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran
2091011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// Returns the NetId that will be set when a socket connect()s. This is the bypassable VPN that
2101011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// applies to the user if any; otherwise, the default network.
2111011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran//
2121011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// In general, we prefer to always set the default network's NetId in connect(), so that if the VPN
2131011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// is a split-tunnel and disappears later, the socket continues working (since the default network's
2141011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// NetId is still valid). Secure VPNs will correctly grab the socket's traffic since they have a
2151011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// high-priority routing rule that doesn't care what NetId the socket has.
2161011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran//
2171011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// But bypassable VPNs have a very low priority rule, so we need to mark the socket with the
2181011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// bypassable VPN's NetId if we expect it to get any traffic at all. If the bypassable VPN is a
2191011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// split-tunnel, that's okay, because we have fallthrough rules that will direct the fallthrough
2201011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// traffic to the default network. But it does mean that if the bypassable VPN goes away (and thus
2211011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// the fallthrough rules also go away), the socket that used to fallthrough to the default network
2221011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran// will stop working.
2231011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranunsigned NetworkController::getNetworkForConnect(uid_t uid) const {
224a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak    android::RWLock::AutoRLock lock(mRWLock);
225e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
2261011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (virtualNetwork && !virtualNetwork->isSecure()) {
227e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran        return virtualNetwork->getNetId();
228a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak    }
2291011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return mDefaultNetId;
230a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
231a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
232e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranunsigned NetworkController::getNetworkForInterface(const char* interface) const {
233f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
23436ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    for (const auto& entry : mNetworks) {
2354043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        if (entry.second->hasInterface(interface)) {
2364043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran            return entry.first;
2374043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        }
2384043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    }
23935c77e32b27694a138e9a7877b9a5b474441c58bPaul Jensen    return NETID_UNSET;
240a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak}
241a0efaece8c05370f201efe099a537ceb014c6fdfSzymon Jakubczak
242070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandranbool NetworkController::isVirtualNetwork(unsigned netId) const {
243070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
244070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
245070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran    return network && network->getType() == Network::VIRTUAL;
246070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran}
247070b2d296de30e3dbc68c21f542acb1f2914d870Sreeram Ramachandran
248e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranint NetworkController::createPhysicalNetwork(unsigned netId, Permission permission) {
249f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
250f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("invalid netId %u", netId);
25196f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return -EINVAL;
2525c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
2535c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
254f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (isValidNetwork(netId)) {
255f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("duplicate netId %u", netId);
256f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        return -EEXIST;
2575c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
2585c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
25948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    PhysicalNetwork* physicalNetwork = new PhysicalNetwork(netId, mDelegateImpl);
260f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (int ret = physicalNetwork->setPermission(permission)) {
261f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("inconceivable! setPermission cannot fail on an empty network");
262f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        delete physicalNetwork;
26396f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return ret;
264ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
265ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
266f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
26736ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    mNetworks[netId] = physicalNetwork;
26896f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti    return 0;
2695c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran}
2705c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
27195684ba176a9fe5ea59207d7202e47fa12bbfdbeSreeram Ramachandranint NetworkController::createVirtualNetwork(unsigned netId, bool hasDns, bool secure) {
2724043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
2734043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        ALOGE("invalid netId %u", netId);
2744043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        return -EINVAL;
2754043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    }
2764043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran
2774043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    if (isValidNetwork(netId)) {
2784043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        ALOGE("duplicate netId %u", netId);
2794043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran        return -EEXIST;
2804043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    }
2814043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran
2824043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
28348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    if (int ret = modifyFallthroughLocked(netId, true)) {
28448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        return ret;
28548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
28695684ba176a9fe5ea59207d7202e47fa12bbfdbeSreeram Ramachandran    mNetworks[netId] = new VirtualNetwork(netId, hasDns, secure);
2874043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran    return 0;
2884043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran}
2894043f01f8e25f24246efadc710ad7440aab75529Sreeram Ramachandran
290f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::destroyNetwork(unsigned netId) {
291738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (netId == LOCAL_NET_ID) {
292738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("cannot destroy local network");
29396f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return -EINVAL;
294ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
295738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!isValidNetwork(netId)) {
296738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
297738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
298738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
299ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
300f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    // TODO: ioctl(SIOCKILLADDR, ...) to kill all sockets on the old network.
30196f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti
302f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
303f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
304f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (int ret = network->clearInterfaces()) {
30596f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti        return ret;
306ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
307f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (mDefaultNetId == netId) {
30836ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->removeAsDefault()) {
309f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            ALOGE("inconceivable! removeAsDefault cannot fail on an empty network");
310f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
311f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        }
312f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        mDefaultNetId = NETID_UNSET;
31348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    } else if (network->getType() == Network::VIRTUAL) {
31448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = modifyFallthroughLocked(netId, false)) {
31548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
31648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
317f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    }
31836ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    mNetworks.erase(netId);
319f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    delete network;
320f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    _resolv_delete_cache_for_net(netId);
321f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return 0;
322f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran}
323ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
324f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::addInterfaceToNetwork(unsigned netId, const char* interface) {
325f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (!isValidNetwork(netId)) {
326738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
327738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
328ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen    }
329ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
330e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    unsigned existingNetId = getNetworkForInterface(interface);
331f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    if (existingNetId != NETID_UNSET && existingNetId != netId) {
332f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("interface %s already assigned to netId %u", interface, existingNetId);
333f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        return -EBUSY;
334a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen    }
335a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen
336f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
337f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return getNetworkLocked(netId)->addInterface(interface);
338ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen}
339ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen
340f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::removeInterfaceFromNetwork(unsigned netId, const char* interface) {
34172604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandran    if (!isValidNetwork(netId)) {
342738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
343738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
3445c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
3455c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
346f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
347f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    return getNetworkLocked(netId)->removeInterface(interface);
348f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran}
3495c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
350f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram RamachandranPermission NetworkController::getPermissionForUser(uid_t uid) const {
351f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
352ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    return getPermissionForUserLocked(uid);
353f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran}
3545c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
355f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranvoid NetworkController::setPermissionForUsers(Permission permission,
356f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                              const std::vector<uid_t>& uids) {
357f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
358f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    for (uid_t uid : uids) {
359ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran        mUsers[uid] = permission;
3605c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran    }
3615c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran}
3625c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran
363e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranbool NetworkController::canUserSelectNetwork(uid_t uid, unsigned netId) const {
364f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
3651011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return canUserSelectNetworkLocked(uid, netId);
366379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran}
367379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
368f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandranint NetworkController::setPermissionForNetworks(Permission permission,
369f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                                const std::vector<unsigned>& netIds) {
370f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
371f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran    for (unsigned netId : netIds) {
37236ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        Network* network = getNetworkLocked(netId);
373738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (!network) {
374738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("no such netId %u", netId);
375738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            return -ENONET;
376738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        }
377738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        if (network->getType() != Network::PHYSICAL) {
378738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti            ALOGE("cannot set permissions on non-physical network with netId %u", netId);
37996f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti            return -EINVAL;
380379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran        }
381379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
382f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        // TODO: ioctl(SIOCKILLADDR, ...) to kill socets on the network that don't have permission.
383379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
38436ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran        if (int ret = static_cast<PhysicalNetwork*>(network)->setPermission(permission)) {
385f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran            return ret;
386379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran        }
387379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran    }
38896f261e8b28048b8cb48f5a4e81822c73bb813f4Lorenzo Colitti    return 0;
389379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran}
390379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran
391b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandranint NetworkController::addUsersToNetwork(unsigned netId, const UidRanges& uidRanges) {
392b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
39336ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
394738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!network) {
395738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
396738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
397738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
398738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (network->getType() != Network::VIRTUAL) {
399738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("cannot add users to non-virtual network with netId %u", netId);
400b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return -EINVAL;
401b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
40236ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    if (int ret = static_cast<VirtualNetwork*>(network)->addUsers(uidRanges)) {
403b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return ret;
404b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
405b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    return 0;
406b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran}
407b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran
408b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandranint NetworkController::removeUsersFromNetwork(unsigned netId, const UidRanges& uidRanges) {
409b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
41036ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
411738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!network) {
412738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
413738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
414738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
415738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (network->getType() != Network::VIRTUAL) {
416738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("cannot remove users from non-virtual network with netId %u", netId);
417b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return -EINVAL;
418b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
41936ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    if (int ret = static_cast<VirtualNetwork*>(network)->removeUsers(uidRanges)) {
420b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran        return ret;
421b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    }
422b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran    return 0;
423b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran}
424b1425cc09f8a29350520db0d4f489331df5a689bSreeram Ramachandran
425f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint NetworkController::addRoute(unsigned netId, const char* interface, const char* destination,
426f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                const char* nexthop, bool legacy, uid_t uid) {
42738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    return modifyRoute(netId, interface, destination, nexthop, true, legacy, uid);
4287619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
4297619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
430f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint NetworkController::removeRoute(unsigned netId, const char* interface, const char* destination,
431f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                   const char* nexthop, bool legacy, uid_t uid) {
43238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
4337619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
4347619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
435e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranbool NetworkController::canProtect(uid_t uid) const {
436e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
437e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    return ((getPermissionForUserLocked(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) ||
438e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran           mProtectableUsers.find(uid) != mProtectableUsers.end();
439e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran}
440e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran
44189dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandranvoid NetworkController::allowProtect(const std::vector<uid_t>& uids) {
44289dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
44389dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    mProtectableUsers.insert(uids.begin(), uids.end());
44489dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran}
44589dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran
44689dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandranvoid NetworkController::denyProtect(const std::vector<uid_t>& uids) {
44789dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    android::RWLock::AutoWLock lock(mRWLock);
44889dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    for (uid_t uid : uids) {
44989dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran        mProtectableUsers.erase(uid);
45089dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran    }
45189dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran}
45289dad013e4dd98434b0409a84567f38782894029Sreeram Ramachandran
453e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandranbool NetworkController::isValidNetwork(unsigned netId) const {
454e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    android::RWLock::AutoRLock lock(mRWLock);
455e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    return getNetworkLocked(netId);
456e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran}
457e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran
458f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram RamachandranNetwork* NetworkController::getNetworkLocked(unsigned netId) const {
45936ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    auto iter = mNetworks.find(netId);
46036ed53e37b2639681055b2d3d8777241e7dd6982Sreeram Ramachandran    return iter == mNetworks.end() ? NULL : iter->second;
4617619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
4627619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
463e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram RamachandranVirtualNetwork* NetworkController::getVirtualNetworkForUserLocked(uid_t uid) const {
464e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    for (const auto& entry : mNetworks) {
465e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran        if (entry.second->getType() == Network::VIRTUAL) {
466e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran            VirtualNetwork* virtualNetwork = static_cast<VirtualNetwork*>(entry.second);
467e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran            if (virtualNetwork->appliesToUser(uid)) {
468e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran                return virtualNetwork;
469e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran            }
470e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran        }
471e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    }
472e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    return NULL;
473e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran}
474e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran
475ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram RamachandranPermission NetworkController::getPermissionForUserLocked(uid_t uid) const {
476ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    auto iter = mUsers.find(uid);
477ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    if (iter != mUsers.end()) {
478ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran        return iter->second;
479ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    }
480ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran    return uid < FIRST_APPLICATION_UID ? PERMISSION_SYSTEM : PERMISSION_NONE;
481ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran}
482ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran
4831011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandranbool NetworkController::canUserSelectNetworkLocked(uid_t uid, unsigned netId) const {
4841011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Network* network = getNetworkLocked(netId);
4851011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    // If uid is INVALID_UID, this likely means that we were unable to retrieve the UID of the peer
4861011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    // (using SO_PEERCRED). Be safe and deny access to the network, even if it's valid.
4871011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (!network || uid == INVALID_UID) {
4881011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        return false;
4891011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
4901011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Permission userPermission = getPermissionForUserLocked(uid);
4911011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if ((userPermission & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
4921011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        return true;
4931011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
4941011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (network->getType() == Network::VIRTUAL) {
4951011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        return static_cast<VirtualNetwork*>(network)->appliesToUser(uid);
4961011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
4971011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    VirtualNetwork* virtualNetwork = getVirtualNetworkForUserLocked(uid);
4981011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    if (virtualNetwork && virtualNetwork->isSecure() &&
4991011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran            mProtectableUsers.find(uid) == mProtectableUsers.end()) {
5001011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran        return false;
5011011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    }
5021011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    Permission networkPermission = static_cast<PhysicalNetwork*>(network)->getPermission();
5031011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran    return (userPermission & networkPermission) == networkPermission;
5041011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran}
5051011b4941d96d9fd90bc7243be387b63ec775936Sreeram Ramachandran
506f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint NetworkController::modifyRoute(unsigned netId, const char* interface, const char* destination,
507f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran                                   const char* nexthop, bool add, bool legacy, uid_t uid) {
508738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!isValidNetwork(netId)) {
509738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("no such netId %u", netId);
510738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENONET;
511738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
512e09b20aee85f1dfd8c18c3d8581ac875d939ba70Sreeram Ramachandran    unsigned existingNetId = getNetworkForInterface(interface);
513738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (existingNetId == NETID_UNSET) {
514738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("interface %s not assigned to any netId", interface);
515738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -ENODEV;
516738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
517738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (existingNetId != netId) {
518f4f6c8de3f091be4b91a5a9d7f14e8882ec6d502Sreeram Ramachandran        ALOGE("interface %s assigned to netId %u, not %u", interface, existingNetId, netId);
519f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti        return -ENOENT;
5207619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran    }
5217619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran
52238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    RouteController::TableType tableType;
52387475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran    if (netId == LOCAL_NET_ID) {
52487475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran        tableType = RouteController::LOCAL_NETWORK;
52587475a1471373b72ffc9f81f17dfd7884723fa86Sreeram Ramachandran    } else if (legacy) {
526ed4bd1f7d219f9f5f56763ea02cf4947e78397f6Sreeram Ramachandran        if ((getPermissionForUser(uid) & PERMISSION_SYSTEM) == PERMISSION_SYSTEM) {
5275009d5ef3fbcdc69d772b528fd22184b7d605afaSreeram Ramachandran            tableType = RouteController::LEGACY_SYSTEM;
52838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran        } else {
5295009d5ef3fbcdc69d772b528fd22184b7d605afaSreeram Ramachandran            tableType = RouteController::LEGACY_NETWORK;
53038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran        }
53138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    } else {
53238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran        tableType = RouteController::INTERFACE;
53338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran    }
53438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran
535eb27b7ec10faf47a93fbc2863092cc667b05e252Sreeram Ramachandran    return add ? RouteController::addRoute(interface, destination, nexthop, tableType) :
536eb27b7ec10faf47a93fbc2863092cc667b05e252Sreeram Ramachandran                 RouteController::removeRoute(interface, destination, nexthop, tableType);
5377619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran}
53848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran
53948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandranint NetworkController::modifyFallthroughLocked(unsigned vpnNetId, bool add) {
54048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    if (mDefaultNetId == NETID_UNSET) {
54148e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        return 0;
54248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
54348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    Network* network = getNetworkLocked(mDefaultNetId);
544738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (!network) {
54548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        ALOGE("cannot find previously set default network with netId %u", mDefaultNetId);
54648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        return -ESRCH;
54748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
548738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    if (network->getType() != Network::PHYSICAL) {
549738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        ALOGE("inconceivable! default network must be a physical network");
550738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti        return -EINVAL;
551738c93ee075354ffafb3a8ceef76e9aa711f057bLorenzo Colitti    }
55248e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    Permission permission = static_cast<PhysicalNetwork*>(network)->getPermission();
55348e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    for (const auto& physicalInterface : network->getInterfaces()) {
55448e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        if (int ret = mDelegateImpl->modifyFallthrough(vpnNetId, physicalInterface, permission,
55548e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran                                                       add)) {
55648e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran            return ret;
55748e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran        }
55848e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    }
55948e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran    return 0;
56048e19b037e7e20674048ef76bf31ce65c741347cSreeram Ramachandran}
561